-
Notifications
You must be signed in to change notification settings - Fork 4
Signal and pump
Sometimes human's input are the async action we want to deal with, for example when you want to validate a large form, or write a interactive game, take a few examples on jsbin:
Action
's solution to these problems are signal and pump:
var Action.signal = new Action(function(cb){
return cb;
})
That's all the code of signal! it's just a special Action
which never call the cb
, instead it return cb
directly. Let see it's in action:
var logSignal = Action.signal
.guard(function(err){
console.log(err.message);
return false;
})
.next(function(data){
console.log(data);
return true;
});
var logPump = logSignal.go()
Make sure you read Return value of go, when you fired a signal with go
, you get a pump back, which is the callback chain you built with next
and guard
. It's easy to see logPump
above is equivalent to:
function(data){
if (data instance of Error){
console.log(err.message);
return false;
} else {
console.log(data);
return true;
}
}
Note we skip the instanceof Action
stuff, Now let pump a value into it:
logPump('hello world')
// hello world
logPump(new Error('damn'))
// damn
If you want to sent a value to backend to do validation, just return a validation Action
inside next
:
var logSignal = Action.signal
.next(function(data){
return someAsyncValidation(data);
// this should be a Action
}
.next(function(data){
console.log('The validation result is:' + data);
});
Since a signal is just an Action
, any Action
can be easily composed into a signal, and you can connect one signal to another signal's pump like this:
composedSignal = signalOne.next(signalTwo.go())
Another intereting thing about signal is, it's an Action
never fired unless we pump something into it, so now controll comes back to us, it can be fired multiple times, so we have a special combinator for signals:
var pumps = Action.fuseSignal([ logSignal, logSignal ])
.next(function(data){
console.log(data[0], data[1]);
})
.go()
setTimeout(pumps[0], 100, 'foo');
setTimeout(pumps[1], 1000, 'bar');
// after 100ms, 'foo' will be logged.
// after 1000ms, 'bar' will be logged.
// after 'bar' was logged, true, true will also be logged.
setTimeout(pumps[1], 2000, 'bar');
// true, true
setTimeout(pumps[1], 3000, new Error 'testError');
// true, false
This combinator combine an Array of signals into one, and you got a pumps array using go
, now only if you pumped all the pumps, the composed signal will be pumped. It's different to Action.all
, after all pumps have been pumped, fused signal will be continue pumped everytime you pump a value into it.