1

help please:

For example i have 20 Timeouts, created by window.setTimeout and i want that they run one after the other:

call timeout 1 => after finish call timeout 2 => after finish call timeout 3 and so on.

Generally there is an array of functions and the number of timeouts not fixed.

my function with deferred:

function someFunction(index) {
   console.log("someFunction called, index = " + index);
   var $deferred = $.Deferred();

   window.setTimeout(function () {
       $deferred.resolve();
   }, 2000);

   return $deferred.promise();
}

for loop:

var $deferred;
$(someArray).each(function (index) {
    if (!$deferred) {
        $deferred = someFunction(index);
    } else {
        $deferred.then(function () {
            return someFunction(index);
        });
    }
});

all the others are run immediately without in the chain

3 Answers3

1

If you want to chain them one after the other, you'd have to do this:

var $deferred;
$(someArray).each(function (index) {
    if (!$deferred) {
        $deferred = someFunction(index);
    } else {
        $deferred = $deferred.then(function () {
            return someFunction(index);
        });
    }
});

What you were doing is putting all the .then() handlers on the same deferred which will run them all in parallel, not serially. What you need is the equivalent of p.then(...).then(...).then(...). Since each .then() returns a new promise, you need to chain to the next link in the chain.


You may find this design pattern a little simpler for iterating through an array sequentially with an async operation that generates a promise:

someArray.reduce(function(p, item) {
    return p.then(function() {
        return someFunction(item);
    });
}, $.Deferred().resolve()).then(function() {
    // all done here
});

Working demo: http://jsfiddle.net/jfriend00/uusjs3mt/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • `setTimeout` duration not applied as expected at `.reduce()` version – guest271314 Nov 13 '15 at 07:35
  • Yes , was 1.7.2 at `console` http://jsfiddle.net/59sn1u31/ ; 1.11.0 http://jsfiddle.net/59sn1u31/1/ – guest271314 Nov 13 '15 at 07:38
  • Yes , tried at `.reduce()` version at `console` , SO uses 1.7.1 ; see also http://stackoverflow.com/questions/32790917/jquery-deferred-promises-executing-out-of-order – guest271314 Nov 13 '15 at 07:46
  • @guest271314 -You're posting cryptic comments that I don't understand. If you want help, please use words to describe what you're asking about or what else you want help with. – jfriend00 Nov 13 '15 at 07:48
  • 1
    @guest271314 - if you want to use reliable, predictable promises, I'd suggest only a recent version of jQuery, a browser that supports ES6 promises or a Promise library like Bluebird. – jfriend00 Nov 13 '15 at 07:50
  • Attempted to convey that `.reduce()` version of your post did not return expected result after trying at `console` . Then reflected that SO uses version 1.7.1 of jQuery , which returns different results than 1.8+. Your `js` pieces do return values that are expected with jQuery version 1.8+ – guest271314 Nov 13 '15 at 07:52
  • @guest271314 - OK, now I understand what you're saying. Are you set with what's in the answer now? Or are there any more questions about it? – jfriend00 Nov 13 '15 at 07:54
  • Yes . One Question: when trying `.reduce()` method what is appropriate approach to accumulate return values of fulfilled , rejected promises to be available at `.then()` following `.reduce()` ? – guest271314 Nov 13 '15 at 07:59
  • @guest271314 - There are multiple options for accumulating results depending upon exactly what you're trying to do and what you want the output to be. This would take a more involved answer. I'd suggest you ask a separate question where that could be addressed. – jfriend00 Nov 13 '15 at 08:07
  • @jfriend00 http://stackoverflow.com/questions/33688342/how-to-return-accumulated-returned-promise-values-as-array-to-then-following-ar – guest271314 Nov 13 '15 at 08:19
0

Try using $.queue() , $.dequeue() , $.map()

function someFunction(index) {
  console.log("someFunction called, index = " + index);
  var $deferred = $.Deferred();

  window.setTimeout(function() {
    $deferred.resolve();
  }, 2000);

  return $deferred.promise();
}

var someArray = [1, 2, 3, 4, 5];

$.queue(someArray, "dfd", $.map(someArray, function(value, index) {
  return function(next) {
    someFunction(index).then(next)
  }
}));
$.dequeue(someArray, "dfd");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
guest271314
  • 1
  • 15
  • 104
  • 177
0

Both methods are working:

$.queue(someArray, "dfd", $.map(someArray, function(value, index) {
  return function(next) {
    someFunction(index).then(next)
  }
}));
$.dequeue(someArray, "dfd");

and

someArray.reduce(function(p, item) {
    return p.then(function() {
        return someFunction(item);
    });
}, $.Deferred().resolve()).then(function() {
    // all done here
});
  • The protocol here on StackOverflow is not to post your own answer that just duplicates info other's have posted. If your question has been answered, you can select the best answer by clicking the green checkmark to the left of that answer and you can comment on any answer. Once you earn more reputation points, you can upvote any answer that helped you. – jfriend00 Nov 13 '15 at 08:09