1

Is there any mean to make this more elegant using other solutions (jquery is fine)?

Important in my case is that respective executions are only triggered if the previous ones have been terminated.

seqExe(["item one", "item two", "item three", "item four", "item five"])

function seqExe(corpus) {
    var i = -1,
        len = corpus.length,
        defer = jQuery.Deferred(),
        promise = defer.promise();

    while(++i < len) {
        promise = promise.then((function(item) {
            return function() {
                console.log(item);
                return foo(item);
            }
        }).call(this, corpus[i]));
    }

    promise.then(function() {
        console.log("Done");
    }, function() {
        console.error("Failed");
    });

    return defer.resolve();
}

function foo(item) {
    var defer = jQuery.Deferred();
    window.setTimeout(
        function() {
            defer.resolve()
            console.log(item);
        }, Math.random() * 2000 + 1000);

    return defer.promise();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

Supposed output should be:

item one
item one
item two
item two
item three
item three
item four
item four
item five
item five
Done
0

1 Answer 1

2

This is an ideal candidate for using reduce. Furthermore your initial promise -- which you want to resolve immediately -- can be just $.when(), and will become the start value of the reduce call:

seqExe(["item one", "item two", "item three", "item four", "item five"])

function seqExe(corpus) {
    return corpus.reduce(function (p, item) {
        return p.then(function () {
            console.log(item + ' pending');
            return foo(item);
        });
    }, $.when())
    .then(function(){
        console.log("Done");
    }, function(){
        console.log("Failed");
    });
}

function foo(item) {
    var defer = new $.Deferred();
    window.setTimeout(
        function() {
            defer.resolve()
            console.log(item + ' resolved');
        }, Math.random() * 2000 + 1000);
    return defer.promise();
}
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>

Note that in some jQuery versions (I see this in 2.1.1) the then callbacks are executed synchronously, which would give the wrong output order. This is fixed in jQuery 3 (I tried 3.1.1, which I also linked to in the above snippet).

Here is how you would do it with native ES6 promises:

seqExe(["item one", "item two", "item three", "item four", "item five"])

function seqExe(corpus) {
    return corpus.reduce(function (p, item) {
        return p.then(function () {
            console.log(item + ' pending');
            return foo(item);
        });
    }, Promise.resolve())
    .then(function(){
        console.log("Done");
    }, function(){
        console.log("Failed");
    });
}

function foo(item) {
    return new Promise(function (resolve) {
        window.setTimeout(function() {
            resolve();
            console.debug(item + ' resolved');
        }, Math.random() * 2000 + 1000);
    });
}

Sign up to request clarification or add additional context in comments.

4 Comments

What do you mean by "then callbacks are executed synchronously, which would give the wrong output order."? That only could happen on already-fulfilled promises, i.e. $.when(), but everything after the first foo() call is chained.
@Bergi, I meant that if in the snippet I posted, I linked to jQuery version 2.1.1 instead of 3.1.1, the order of the output changed. NB: I made a correction now, because I had first moved the second console.log, and forgot to put it back in place (after resolve).
Ah, that. Right, you'd have to place the console.debug in front of the deferred.resolve() call for that.
Indeed, it was what I tried before I realised it was a peculiar behaviour of jQuery 2.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.