-1

I came upon this script from Google search at jQuery Deferred and Promise for sequential execution of synchronous and asynchronous funcitons .

This may solve my issue on executing the script in sequiental order. But the problem I have with then() function is I have no way of knowing how many time can I call this function. I can call the function a() 3 times, next time, I can call it 20 times, etc. So, that won't work with then(). then() function doesn't allow the array stack. So, what do you people do to to make this concept work?

fucntion a(counter)
{
    $deferred = $.Deferred();

    //Run some scripts here...
    alert(counter);

    $deferred.resolve();
    return $deferred;
}
function Test()
{
    var d = $.Deferred(), 
    p=d.promise();
    p.then(a(0)).then(a(1)).then(a(2));
    d.resolve();
    return d;
}

Test().done(function(){ alert('done'); }).fail(function() { alert('fail'); });
Community
  • 1
  • 1
fletchsod
  • 3,181
  • 6
  • 31
  • 58
  • You are passing the `$deferred` returned by `a(N)` to `.then()`. Instead, you will need to pass a callback function, e.g. `.then(a)`. – Bergi Sep 03 '14 at 18:15
  • 1
    I'm not sure what you mean when you refer to calling `Test()` multiple times? What's wrong with that, what happens when you do this that you didn't expect? What do you mean by "*allow the array stack*"? – Bergi Sep 03 '14 at 18:16
  • I updated the question, I mean a(), not Test()... – fletchsod Sep 03 '14 at 18:17
  • Yes, you're calling `a(0); a(1); a(2);` instantly together, which makes the async processes run concurrently. – Bergi Sep 03 '14 at 18:21
  • Yes. How many times to call it is random, the first time, it can be calling the function a() 3 times. Later in the day, it can be calling the function a() 20 times. How many time to call it is done randomly. The $.Deferred.then() doesn't do random # of times to call the function a(). – fletchsod Sep 03 '14 at 18:22
  • 1
    So what's the question? What concept are you trying to "make work"? – Matt Burland Sep 03 '14 at 18:24
  • Sorry for my bad English. My question is how to add then() dynamically without knowing how many times the function a() is called. – fletchsod Sep 03 '14 at 18:29

2 Answers2

2

I think what you are asking is how to chain and unknown number of calls. In that case you can easily loop and just keep adding more .then. For example:

for (var i=0; i < someLimit; i++) {
    p = p.then(a(i));
}

That will chain the calls so they get called one after the other. If you wanted them to execute in parallel, then @jantimon's suggestion of using .when is the way to go.

This works because of how chaining works. A call to .then returns a promise so that you can call .then again on the returned promise. See: http://api.jquery.com/deferred.then/

Matt Burland
  • 42,488
  • 16
  • 89
  • 156
  • Thank you. Yes, chaining having unknown number of calls. I didn't know this would work. – fletchsod Sep 03 '14 at 18:32
  • 1
    I like your solution but this would also execute them in parallel, wouldn't it? – jantimon Sep 03 '14 at 18:34
  • @jantimon: No. `.then` will be executed when the deferred is resolved. So they will execute one after the other. Not to be confused with `.when` – Matt Burland Sep 03 '14 at 18:36
  • 1
    @MattBurland: `a(i)` doesn't return a function, but a promise. It will execute them in parallel, and not wait for anything… – Bergi Sep 03 '14 at 18:39
  • @Bergi: Ah, yeah, I missed that part. But I'm not sure why they are returning a deferred in the first place. – Matt Burland Sep 03 '14 at 19:00
  • @Bergi Okay, you're saying there's a better or simplier way? If so then can you show me one? I'm still learning as I'm trying to avoid the old fashioned callback ways. – fletchsod Sep 03 '14 at 19:08
  • @fletchsod: You can't avoid passing a callback to `then`, the advantage of promises is that you can unnest them. Have a look at [this](http://stackoverflow.com/a/18387432/1048572) or [this](http://stackoverflow.com/a/23650478/1048572) – Bergi Sep 03 '14 at 19:50
1

You could use jQuery.when.
Please note that this would execute multiple asynchronous operations concurrently:

jsFiddle Demo

Given you a function which returns an async promise:

function a(counter, $target) {
    var $deferred = $.Deferred();
    setTimeout(function () {
        $target.text($target.text() + ' ' + counter);
        $deferred.resolve();
    }, 1000);
    return $deferred;
}

In parallel:

function Test1() {
    return $.when($.map([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function (val, i) {
        return a(i, $('#test1'));
    }));
}

Test1().done(function () {
    $('#test1').css('font-weight', 'bold');
}).fail(function () {
    alert('fail');
});

To run it in sequence you will need a promiseLoop helper:

function promiseLoop(arr, callback) {
    return arr.reduce(function (previousPromise, val, i) {
        return previousPromise.then(function (resultArray) {
            return $.when(callback(val, i)).then(function (res) {
                return resultArray.concat([res]);
            });
        });
    }, $.when([]));
}

function Test2() {
    return promiseLoop([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function (val, i) {
        return a(i, $('#test2'));
    });
}


Test2().done(function () {
    $('#test2').css('font-weight', 'bold');
}).fail(function () {
    alert('fail');
});
jantimon
  • 33,244
  • 22
  • 110
  • 172