martes, 6 de octubre de 2015

Queue based on Q promises

So just that,I'm working with promises in JavaScript and at certain point I needed a queue for executing asynchronous tasks. My promises are implemented by q library and my particular requirements are as follows. I implemented this web service client without knowing that no concurrent operations are allowed. In some cases, if you request two operations at the same moment the server will return an error. In my case, an obvious quick solution was to en-queue the method that makes the requests in my client. Something like make it synchronous (similar as java methods can be declared as 'synchronous' when multi threads access it).

I research a little and there are plenty alternatives, most appreciated was the queue utility of async, a library that also use. Nevertheless instead learning how to use it, and because I know this problem can be solved w promises wanted to try something else

I very liked the solution proposed here because is simple so I adapted to use Q promises instead jQuery's. This is the result (working example in node, but should work also in the browser)

var Q = require('q')


var Queue = function () 
{
    var lastPromise = null;

    this.add = function (obj, method, args, context) 
    {
        var methodDeferred = Q.defer(); 
        var queueDeferred = this.setup();
        if(context === undefined) { context = obj; }

        // execute next queue method
        queueDeferred.done(function () 
        {
            // call actual method and wrap output in deferred
            setTimeout(function () 
            {
                obj[method].apply(context, args);
                methodDeferred.resolve();
            }, 100);
        });
        lastPromise = methodDeferred.promise;
    };

    this.setup = function () 
    {
        var queueDeferred = Q.defer(); 

        // when the previous method returns, resolve this one
        if(!lastPromise)
        {
            lastPromise = Q.defer(); 
            lastPromise.resolve();
            lastPromise = lastPromise.promise;
        }
        lastPromise.done(function () 
        {
            queueDeferred.resolve();
        });

        return queueDeferred.promise;
    }
};



var queue = new Queue();
queue.add(console, 'log', ['one']);
queue.add(console, 'log', ['two']);
queue.add(console, 'log', ['three']);
setTimeout(function ()
{
    queue.add(console, 'log', ['four']);
}, 2000);