There are two ways to manage asynchronous requests in Microcosm:
Microcosm implements standard behaviors for Promise resolution; convenient for Promise based AJAX libraries. Whenever an action creator returns a Promise, it will wait for that Promise to resolve/reject:
// Run this code yourself at:
// https://tonicdev.com/57ac614723722e17003526a7/57acbf88a55ecf1200fa3763
var Microcosm = require('microcosm')
var request = require('superagent')
var repo = new Microcosm()
function getSite() {
return request.get('http://code.viget.com/microcosm')
}
repo.addDomain('site', function() {
return {
[getSite]: {
open: () => 'loading',
error: () => 'error',
done: () => 'done'
}
}
})
repo.on('change', function(state) {
console.log(state.site) // loading, done
})
repo.push(getSite)
When Microcosm detects a Promise returned from an action creator, it handles it in the following way:
- Mark the action as
open
. This gives domain handlers a way to subscribe to a loading state. The payload of the action will be the first argument of the parameters passed intorepo.push
. - On resolution, mark the action as
done
and update its payload to that of the resolved Promise. - On failure, mark the action as
error
and update its payload to the associated error.
Microcosm's state management model enables easy clean up of loading
states. Whenever the action moves from open
to done
, Microcosm
re-executes all outstanding actions in the order they were pushed.
To illustrate, when the action creator is first pushed into Microcosm, it inserts an action into Microcosm's historical ledger of all actions like:
1. ajax (open)
Microcosm then enumerates through this list, using domain handlers to
calculate repo state. When the action completes, it moves into a
done
state:
1. ajax (done)
Again, Microcosm rolls forward through the history list, recalculating state for the repo.
Since the action is no longer in an open
state, the
resulting repo state will be as though the loading domain
handler never fired. There's no cleanup.
Promises are easy to use, but they have a couple of problems when representing HTTP requests. Cancellation is difficult, and progress updates are impossible.
Returning a function from an action creator provides a way to tap into the lower level API for an action:
// Run this code yourself
// https://tonicdev.com/57ac614723722e17003526a7/57acbfab74054114008fda70
var Microcosm = require('microcosm')
var request = require('superagent')
var repo = new Microcosm()
function getSite() {
return function(action) {
action.open()
request
.get('http://code.viget.com/microcosm')
.end(function(error, payload) {
if (error) {
action.reject(error)
} else {
action.resolve(payload)
}
})
}
}
repo.addDomain('site', function() {
return {
[getSite]: {
open: () => 'loading',
error: () => 'error',
done: () => 'done'
}
}
})
repo.on('change', function(state) {
console.log(state.site)
})
repo.push(getSite)