Pot.js Deferred Reference

Deferred Reference

Hereafter this section describes about the Pot.Deferred.

Callback Chain

Pot.Deferred is asynchronous processing object that makes it possible to write asynchronous JavaScript callback processes serially.

setTimeout(function() {
    something1();
    setTimeout(function() {
        something2();
        setTimeout(function() {
            something3();
        }, 0);
    }, 0);
}, 0);

This nested process makes like able to write as follows:

begin(something1).then(something2).then(something3);


Try writing a simple asynchronous processing using Pot.Deferred.

begin(function() {
    console.log('begin');
    return wait(2);
}).then(function() {
    console.log('end');
});

This process begins by asynchronously "begin" method. Output 'begin' first in the console and will output 'end' after waits 2 seconds.

If Pot.globalize() is not called, this example same as following code.

Pot.Deferred.begin(function() {
    console.log('begin');
    return Pot.Deferred.wait(2);
}).then(function() {
    console.log('end');
});


(Hereafter, this reference describes as the environment that is called Pot.globalize() for convenience.)

If you have experience in the Deferred other libraries, the following confirm the difference in the function name. (There are also several different interpretations.)

Pot.Deferred MochiKit.Async.Deferred JSDeferred jQuery.Deferred dojo.Deferred
then addCallback(s) next done / then then / addCallback(s)
rescue addErrback error fail addErrback
ensure addBoth - always addBoth
begin callback call resolve resolve / callback
raise errback fail reject reject / errback
cancel cancel cancel - cancel

Pot.Deferred is almost the same behavior as the JSDeferred and the MochiKit.Async.Deferred.


This description is referred from JSDeferred document about the basic reference of the Deferred.

Asynchronous processing also occurs during events such as onclick as well as Ajax and setTimeout.
For example, there is a function for HTTP request, URL as its first argument, and shall require a second argument to the callback function.
If it write without the Deferred, like below.

request('/foo.json', function(fooData) {
    request('/bar.json', function(barData) {
        request('/baz.json', function(bazData) {
            alert([fooData.result, barData.result, bazData.result]);
        });
    });
});

The more request and will become deeply nested function.

If it write with Pot.Deferred this looks like below.

// Assume "request" function requires a URL as first argument
//  and returns a new instance of Deferred.
var result = [];
begin(function() {
    return request('/foo.json').then(function(fooData) {
        result.push(fooData.result);
    });
}).then(function() {
    return request('/bar.json').then(function(barData) {
        result.push(barData.result);
    });
}).then(function() {
    return request('/baz.json').then(function(bazData) {
        result.push(bazData.result);
    });
}).then(function() {
    alert(result);
});

Compared with cases without the Deferred, makes callback processes serially.

However, in this case, repeat the process has closed as well.
The following example can be process any requests.

var urls = ['/foo.json', '/bar.json', '/baz.json'];
var result = [];
Deferred.forEach(urls, function(url) {
    return request(url).then(function(data) {
        result.push(data);
    });
}).then(function() {
    alert(result);
});

You can write like this.

You can write this as more compact and parallel processing, like below.

parallel([
    request('/foo.json'),
    request('/bar.json'),
    request('/baz.json')
]).then(function(result) {
    alert(result);
});

Thus, "parallel" (Pot.Deferred.parallel) can also be used. "parallel" works comparable with the DeferredList in MochiKit and the JSDeferred.parallel method. After all processing then callback is called with results.


The result of the callback function for each chain is passed as an argument to the next value chain by "return" statement.
If callback function has no "return" statement, will be ignored as the result.
In that case, the following is passed to the callback again took over the previous results.
Determine whether there is the "return" statement to directly under the callback function scope.

begin(function() {
    return 'foo';
}).then(function(res) {
    alert(res); // 'foo'

    // Exit this callback without return value.

}).then(function(res) {
    // Taken over the result of the previous chain.
    alert(res); // 'foo'

    // Returns a value.
    return 'bar';
}).then(function(res) {
    alert(res); // 'bar'
});

Exception

Exceptions that occur in asynchronous processing, but you will behave as if nothing had happened.

Pot.Deferred is able to caught this error by "rescue" method.

begin(function() {
    alert('begin');
}).then(function() {
    // Occurs an exception by calling an undefined function.
    undefinedFunc.call();
}).rescue(function(err) {
    // Catch the error.
    alert(err);
}).then(function() {
    // Then process can continue callbacks.
    alert('end');
});

Broadly, this can be handled in such flows.

Caught by "rescue", you can always catch the error even though not next chain.

begin(function() {
    alert(1);
    return 1 + 1;
}).then(function(res) {
    alert(res); // 2
    return res + 1;
}).then(function(res) {
    alert(res); // 3

    // Raise an error.
    throw new Error('error');
}).then(function(res) {
    // This callback will be not called by occurs an error.
    alert(res);
    return res + 1;
}).rescue(function(err) {
    // Catch the error.
    alert(err);
    return 'end';
}).then(function(res) {
    alert(res); // 'end'
});

This example will be alert 1, 2, 3, 'error', 'end'.

"then" function's callback function of first argument will be called if succeed. If occurs an error then callback function will be ignored.


In fact, careful implementation such as all chains with "rescue" will so rare.
So you might not notice that completed implementation with exception possibility on.
For such case, Pot.Deferred will be re-throw when the chain terminated with uncatched error.
This re-throw feature, the exception can be implemented without missing.


You can use "ensure" method on both success and exceptional cases, even if you want to execute a next callback function in any event.

begin(function() {
    return 1;
}).then(function(res) {
    alert(res);
    // Raise an exception at random.
    if (Math.random() * 10 < 5) {
        throw new Error('error');
    } else {
        return res + 1;
    }
}).ensure(function(res) {
    if (isError(res)) {
        alert('Error: ' + res);
    } else {
        alert('Success: ' + res);
    }
    return 'end';
}).then(function(res) {
    alert(res); // 'end'
});

"ensure" is usefull such a success or unknown case, or when you want to execute always.

isError (Pot.isError) function checks whether argument is an Error object.

"then", "rescue" and "ensure" each use the same.
Returned value will use for the next callback function's argument.

If returned value is an instance of the Pot.Deferred then last callback chain's returned value passed to the next callback function argument.

begin(function() {
    return begin(function() {
        return 'ho';
    }).then(function(res) {
        var d = new Deferred();
        return d.then(function() {
            return res + 'ge';
        }).begin();
    });
}).then(function(res) {
    alert(res);
});

This example will alert 'hoge'.

You can nested chain when returned value is an instance of Pot.Deferred.

Destructuring-Assignment

Pot.Deferred's callback chain can Destructuring-Assignment like.

begin(function() {
    // Return as Array
    return [1, 2, 3];

// Match the number of arguments and number of items in an array of results.
}).then(function(a, b, c) {

    debug(a); // 1
    debug(b); // 2
    debug(c); // 3

    return [c, b, a]; // Returns a reverse order

}).then(function(a, b, c) {
    // Be reversed and

    debug(a); // 3
    debug(b); // 2
    debug(c); // 1

    return [c, b, a];

}).then(function(res) { // As usual, gets one argument variable.
    // If you specify one argument variable Destructuring-Assignment will not execute.

    debug(res); // [1, 2, 3]

});


Speed Control

Pot.Deferred can control the execution speed of callback chain.

var d = new Deferred();
// Speed down
d.speed('slow');

d.then(function() {
    console.log(1);
}).then(function() {
    console.log(2);
}).then(function() {
    console.log(3);
}).begin();

By doing this, each callback is executed slowly.
This example will display slowly '1', '2' and '3' by console.log().

You can specify speed by the 'speed' method. You can specify speed by the 'speed' method with String or Number (ms) argument value. Refer constant string value following table.

value / method name speed
limp most slowly
doze more slowly
slow slowly
normal normal
fast fast
rapid faster
ninja fastest

Alternatively, you can pass an argument to the constructor as an option.

var d = new Deferred({ speed : 'slow' });

It is also possible to change the speed in the middle of the callback chain.

var d = new Deferred();
d.then(function() {
    console.log(1);
}).speed('slow').then(function() {
    console.log(2);
    return 2 + 1;
}).speed(5000).then(function(res) {
    console.log(res); // 3
}).begin();

As in the example above, chain can taking over the value of the result and passes to the next callback if the method not needs callback function.
Therefore, the value of the following arguments to pass to the callback even if you used speed(), wait() etc. will not be lost the value.

If you want to handle some heavy processing to split, you can reduce the load by specifying the speed.

begin(function() {
    return someHeavyProcess();
}).speed('slow').then(function(res) {
    return moreHeavyProcess(res);
}).speed('doze').then(function(res) {
    return mostHeavyProcess(res);
}).speed('normal').then(function(res) {
    alert(res);
});

It is also possible to put a wait in the middle.

begin(function() {
    return someHeavyProcess();
}).speed('slow').wait(1).then(function(res) {
    return moreHeavyProcess(res);
}).speed('doze').wait(2).then(function(res) {
    return mostHeavyProcess(res);
}).speed('normal').then(function(res) {
    alert(res);
});

wait() is treats argument as the number of seconds. Note that because it is not in milliseconds.

Fire Chain

Pot.Deferred's chain can start by .begin() method.

begin (Pot.Deferred.begin) as a function is a shortcut to create an instance of Pot.Deferred, to start the chain.
Note that Pot.Deferred.begin() and Pot.Deferred.prototype.begin() are different.

var d = new Deferred();
d.then(function() {
    alert('hoge');
});

This example never alert 'hoge'.
Just registered a callback to variable 'd' simply.

If you add code like the following, will be started the callback chain.

d.begin();

You can also set the value of an argument.

var d = new Deferred();
d.then(function(value) {
    alert(value);
}).begin('hoge');

In this example, will be alert 'hoge'.

The argument value can be passed as the next (in this case, first) callback's arguments.

You can start with the .raise() method instead of the .begin() method if you want to treat any error by the situation.

var d = new Deferred();
d.then(function() {
    // On success.
    successFunc();
}).rescue(function() {
    // On error.
    errorFunc();
}).ensure(function() {
    // Final processing.
    finallyFunc();
});

// Validate and succeed if passes the check.
if (check()) {
    d.begin();
} else {
    // Raise a error.
    d.raise();
}

You can start the callback chain with an error.
Since starting from the error, if there is a .then() the first callback will be ignored.

The .raise()'s argument value can be passed like .begin() as the next callback's arguments.

Deferrize function

Some program might be need deferrize (i.e. convert to Deferred) to the function.
Deferrize is convert to the function to be returned as an instance of the Pot.Deferred.

The following example processes the asynchronous using XMLHttpRequest.

function request(url, options) {
    var deferred = new Deferred();
    var xhr = new XMLHttpRequest();
    if (options.queryString) {
        url += options.queryString;
    }
    xhr.open(options.method, url, true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                deferred.begin(xhr);
            } else {
                deferred.raise(xhr);
            }
        }
    };
    deferred.canceller(function() {
        xhr.abort();
    });
    xhr.send(options.sendContent || null);
    return deferred;
}

This 'request' function simple version that works like Pot.request() function.

Deferrized function must be returned an instance of Deferred.

Call the .begin() if request succeed. And, call .raise() if request failed.
When you define a function, will be a more appropriate process, by explicit error handling.

"canceller()" method can register callback function that will called when cancelled chain.
You can cancel the chain like below.

deferred.cancel();

"canceller()" is possible register one or more callbacks by stackable handling.


There's another way of Deferred conversion function.
A function named deferrize (Pot.Deferred.deferrize) is defined in Pot.js / PotLite.js.

// deferrize window.setTimeout.
var timer = deferrize(window, 'setTimeout');

// arguments same as setTimeout usage.
timer(function() {
    debug(1);
}, 5000).then(function() {
    debug(2);
});

The above example, Deferrize a setTimeout, and run it.

This result, wait 5 seconds, the output is in the order of 1, 2 on the console by the function debug.

If target function takes a callback, then "deferrize()" will start the Deferred when finished its processing. If target function needless the callback, "deferrize()" will be start the Deferred when finished all of processes. Starts with .raise() if an error occured.
Therefore, most functions can be convert to Deferred by deferrize().

You can deferrize more complex function by your own code using Pot.Deferred object functions.

Iterator

Pot.js implemented focusing on the asynchronous loop and iteration with Pot.Deferred.

We are strongly respecting an overview of the JSDeferred.

via Introduction to JSDeferred:

"Speeding Up" JavaScript

When you say "Speed Up" JavaScript, it is very important to reduce user's stress rather than speeding up of the process.

No matter how fast the process is, if it blocks the UI thread for a long time it gives a big stress to the user. In JavaScript, shortest blocking time of UI thread is more important than the overall time of execution.

Also nested loop will be heavy and the infinity loop might be crashes the browser.

Therefore, We implemented the asynchronous iterators (forEach, map, reduce, filter, some, every, repeat, forEver etc.) with Pot.Deferred.
Asynchronous iterator calculates the heavy processing of each loop automatically and optimizes the process to execute without burdening the CPU.
And we have with the goal to reduce further stress to the UI.

All iterators can execute asynchronous and synchronous. And its can execute on Deferred chain.

Example JavaScript for-in:

for (var key in object) {...}

Case of Pot.forEach (synchronous):

forEach(object, function(value, key) {...});

Case of Pot.Deferred.forEach (asynchronous):

Deferred.forEach(object, function(value, key) {...});

Asynchronous iterator returns an instance of Pot.Deferred.
If Pot.globalize()d, you can call 'Pot.Deferred.forEach' as 'Deferred.forEach'.

Case of execute on Deferred chain:

(new Pot.Deferred()).forEach(function(value, key) {...}).begin( object );

If you execute loop to the array that has 10,000 or more items, about burdening to the CPU will be great difference between Pot.js asynchronous iterator (e.g. Pot.Deferred.forEach) and JavaScript loop (for-in, while etc.).
Also, you can avoid "Unresponsive script" alert on the Web browser by using Pot.js asynchronous iterator.

All related to the Pot.js asynchronous iterator, you can adjust the speed.
If you want to run slowly, like as follows:

Deferred.forEach.slow(obj, function() {...});

If you want to run fast, like as follows:

Deferred.forEach.fast(obj, function() {...});

Refer speed value table if you want to use other speed.

Also it is might be the frequent load and freeze by burdening process on web browser not only time-consuming loop.
Such handle also, you can be fixed by cutback processing and run without burdening the CPU.

When handling a large amount of DOM elements, for example:

// Suppose the HTML page that is larger and it has many elements.
var elems = document.getElementsByTagName('*');

The conventional synchronization loop will not be give a rest for thread till end of loop.

var len = elems.length;
for (var i = 0; i < len; i++) {
    var elem = elems[i];
    someHeavyProcess(elem); // Some heavy processing function.
}

This example code will crazy loops even if web browser is freezed.

You can write loop with the Pot.Deferred object.

Deferred.repeat(elems.length, function(i) {
    var elem = elems[i];
    someHeavyProcess(elem); // Some heavy processing function.
});

Most load will be reduced by this refactoring. Pot.js's iterator calculate the load of processing for each loop. If CPU utilization is over to some extent, will be returned control to the web browser, and then adjusted so as not to monopolize the thread.

Also, you can use forEach method.

Deferred.forEach(elems, function(elem) {
    someHeavyProcess(elem); // Some heavy processing function.
});

If someHeavyProcess() is able to divide to some callbacks, you can write other way.

Deferred.forEach(elems, function(elem) {
    return begin(function() {
        someHeavyProcess1(elem);
    }).wait(1).then(function() {
        someHeavyProcess2(elem);
    }).wait(1).then(function() {
        someHeavyProcess3(elem);
    });
});

Split the processing of cases like this, you can connected with a method such as the chain .wait() etc.

Note:
begin() will be returned an instance of the Pot.Deferred. Callback function should has a return statement if you want to run asynchronous processing in the asynchronous iterator (e.g. Pot.Deferred.forEach) for consistent of each iteration.

If load balancing is still necessary, you can eliminate by specifying the speed of slow (refer speed control table's value).

Deferred.forEach.slow(elems, function(elem) {
    someHeavyProcess(elem);
});

All of Pot.js's asynchronous iterator can control to speed. (e.g. 'forEach.rapid(function() {...})').

Optimize loop

You can optimize loop by Pot.js's iterator on behalf of the JavaScript iteration.
Example loop function that returns large array:

function someLoop(n, c) {
    var results = [];
    for (var i = 0; i < n; i++) {
        var array = [];
        for (var j = 0; j < c; j++) {
            array[j] = j;
        }
        results[i] = array;
    }
    return results;
}

For example, if you execute like below, function will monopolize the CPU depending on the load in most environments.

var array = someLoop(100000, 1000);

Try deferrize the function.

function someLoopDefer(n, c) {
    var results = [];
    return Deferred.repeat(n, function(i) {
        var array = [];
        for (var j = 0; j < c; j++) {
            array[j] = j;
        }
        results[i] = array;
    }).then(function() {
        return results;
    });
}

As an example, can be converted in this way.
Returns an instance of Pot.Deferred.

someLoopDefer(100000, 1000).then(function(res) {
    var array = res;
});

By this change, instantaneous load is distributed, stable processing is possible.
Instead, the processing time may be extend slightly.

In this way, decentralized loop will be possible without too much consciousness if you use Pot.Deferred iterator.

Stop Iteration

All of Pot.js's iterator can stopped the iteration by throw the StopIteration.

var foo = '';
forEver(function(i) {
    foo += 'foo';
    if (foo.length > 10) {
        throw StopIteration;
    }
});

debug(foo);

This example will be outputs 'foofoofoofoo' by function debug.

forEver (Pot.forEver) iterates callback function until thrown the StopIteration.

If environment already has StopIteration, you can resolve by using Pot.StopIteration.

How to check whether StopIteration:

if (isStopIter(e)) {...}
if (e == StopIteration) {...}
if (e instanceof StopIteration) {...}

We recommend check the StopIteration by Pot.isStopIter function.


All of Pot.js's iterators designed Nested-StopIteration. If you throw StopIteration from nested callback function scope, it will reach the scope of the iterator function running.

var result = [];
begin(function() {
    return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
}).forEach(function(value) {
    return begin(function() {
        var d = new Deferred();
        return d.then(function() {
            if (value > 5) {

                // Because the scope of the iterator
                //  that is running becomes the target,
                //  in this case will reach up to the outermost .forEach().

                throw StopIteration;
            }
            return value * 100;
        }).begin();
    }).then(function(res) {
        result.push(res);
    });
}).then(function() {
    debug(result);
    //  =>  [100, 200, 300, 400, 500]
});