Skip to content
winterland edited this page Oct 29, 2015 · 15 revisions

Action.signal

What if human's input are the async action we want to deal with? for example you want to validate a form with different conditions, and the form will pass validation only when each field passed. Unlike most async solutions which are focus on data processing, Action have a very elegant solution to that a problem too:

var Action.signal = new Action(function(cb){
    return cb;
})

This's the core of a signal, it's a special Action which never call the cb, instead it return cb directly. What does that suppose to mean?

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 before! we use pump to mark the return value of firing a signal. It's easy to see logPump above is just a function composed by guard and next, it's equivalent to:

function(data){
    if (data instance of Error){
        console.log(err.message);
        return false;
    } else {
        console.log(data);
        return true;
    }
}

Here we skip the instanceof Action stuff, actually you can return an Action inside next and guard, because a signal is just an Action, any Actions can be easily composed into a signal. Now you can pump a value to the signal using logPump anywhere you want:

logPump('hello world')
// hello world

logPump(new Error('damn'))
// damn

If you want to sent a value to backend to do validation, just wrap the validation inside an Action like this:

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);
});

The intereting thing about signal is that, it's an Action never fired unless we pump something into it, so it gives controll back to us, it can be fired multiple times, so we have some special combinators 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 in that since user now have full controll of pumps, fused signal will be pumped everytime if you continue pumping value into it after all pumps have been pumped.

Clone this wiki locally