Search code examples
javascriptjqueryqueuejquery-deferred

Is it possible to queue in succesion an array of functions that return promises?


Have the next example:

function exec()
{
    var dfd = $.Deferred();

    asyncStuff().then(
    function(res)
    {
        if(res)
        {
            dfd.resolve(true);
        }
        else
        {
            dfd.resolve(false);
        }
    });

 return dfd.promise();
}

var promise_arr = [];
promise_arr.push( exec() );
promise_arr.push( exec() );
promise_arr.push( exec() );
promise_arr.push( exec() );

Promise.all( promise_arr ).then(
function(res)
{
    console.log("finished!");
});

So the functions inside the array are executed almost simoultaneously. This is not good. One must be called only after another finishes in sequence. Is there a way to queue them?

EDIT:

For it to work I had to call an anonymous function inside the for loop, and I took the adventage to stop Its execution whether my promises returned a correct answer. That anonymous function works as a promise factory, check out: https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html

Also, when I push the functions, I had to remove the braces for them to stop executing on pushing them inside the array.

function Exec()
{
    var dfd = $.Deferred();
    
    setTimeout(
    function()
    { 
        console.log("executing OK"); 
        var res_obj = {};
        res_obj.res_value = true;
        dfd.resolve(res_obj);
    }, 1000);
    
    return dfd.promise();
}

function ExecNO()
{
    var dfd = $.Deferred();
    
    setTimeout(
    function()
    { 
        console.log("Executing ERROR"); 
        var res_obj = {};
        res_obj.res_value = false;
        res_obj.res_error = "Ima error func";
        dfd.resolve(res_obj);
    }, 1000);
    
    return dfd.promise();
}

function ExecSincroProcess( promise_arr )
{
    var res_obj = {};
    res_obj.res_value = true;

    var result = Promise.resolve(res_obj);

    promise_arr.forEach(
        function (promiseFunction) 
        {
            result = 
            result.then(
            function(res)
            {
                if (res.res_value)
                {
                    return promiseFunction();
                }
                else
                {
                    return res;
                }
            });
        });

        result.then(
    function(res)
    {
        console.log(res.res_error);
        console.log("finished!");
    });
}

function ExecAll()
{
    var pr_Arr = [];
    pr_Arr.push(Exec);
    pr_Arr.push(Exec);
    pr_Arr.push(ExecNO);
    pr_Arr.push(Exec);
    pr_Arr.push(Exec);
    
    ExecSincroProcess(pr_Arr);
}

Solution

  • There is a way to queue promises. The way I have queued promises in the past is to loop through the array an chain them together with .then clauses:

    ex.

    let promiseChain = Promise.resolve()
    promiseFunctionArray.forEach(promiseFunction => {
        promiseChain = promiseChain.then(promiseFunction)
    })
    
    promiseChain.then(() => {/* do what you want to with the results */})
    

    So your case could look like this:

    function exec()
    {
        var dfd = $.Deferred();
    
        asyncStuff().then(
        function(res)
        {
            if(res)
            {
                dfd.resolve(true);
            }
            else
            {
                dfd.resolve(false);
            }
        });
    
     return dfd.promise();
    }
    
    var promise_arr = [];
    promise_arr.push(exec);
    promise_arr.push(exec);
    promise_arr.push(exec);
    promise_arr.push(exec);
    
    var promiseChain = Promise.resolve()
    promise_arr.forEach(promiseFunction => {
        promiseChain = promiseChain.then(promiseFunction)
    })
    
    promiseChain.then(
    function(res)
    {
        console.log("finished!");
    });