3

This is my sample code:

function out(msg)
{
  $('#output').append(msg + '<br>');
}

var myDeferred = [];
$.each([8, 3, 4, 6, 9, 15, 7, 1], function (index, time)
{
  myDeferred.push($.Deferred(function(dfd)
  {
    setTimeout(function ()
    {
      out(time);
      dfd.resolve();
    }, time * 1000);
  }).promise());
});

$.when.apply($, myDeferred).then(function ()
{
  out('all is done');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>

This output "1 3 4 6 7 8 9 15 all is done", all callback are called at the same time.

But I want "8 3 4 6 9 15 7 1 all is done", all callback are called one after the other.

Someone can help me ?

thanks in advance

dtcSearch
  • 33
  • 4
  • 1
    Can you clarify what you want? Do you want 8 seconds to pass, print a message, then 3 seconds to pass, print a message, ... ? – JuniorCompressor Feb 15 '15 at 13:47
  • What do you mean "all callbacks are called at the same time" - they have different `time` values and different timeouts? – Bergi Feb 15 '15 at 13:47
  • @JuniorCompressor you have a good answer, but is it possible with $.Deferred ? – dtcSearch Feb 15 '15 at 13:51
  • @Bergi when I say that, I speak about the callback in the array myDeferred, not the callback on the setTimeout – dtcSearch Feb 15 '15 at 13:52
  • If you do want the delay to be shown, don't use `$.when` on array, use it on each `$Defered` individually. Not entirely clear what your expectations are – charlietfl Feb 15 '15 at 13:52
  • @dtcSearch: Yes, of course `$.each` is synchronous. Promises don't change that. See [this question](http://stackoverflow.com/q/18386753/1048572) on how to *chain* the array callbacks – Bergi Feb 15 '15 at 13:55
  • ok, thant for your help :) I can't up you're reputation, but when I've the 15 :) I do that ;) @JuniorCompressor you're anwser is approved! – dtcSearch Feb 15 '15 at 14:05
  • @Bergi thanks for the link, I've already read that, but right now, I understand – dtcSearch Feb 15 '15 at 14:06

2 Answers2

3

The problem is that each callback timeout is activated almost at the same time. You can do the following though:

function out(msg)
{
  $('#output').append(msg + '<br>');
}

function foo(index, callback) {
  var time = array[index];
  out(time);
  if (index == array.length - 1)
    callback();
  else
    setTimeout(foo, time * 1000, index + 1, callback);
}

var array = [8, 3, 4, 6, 9, 15, 7, 1];
foo(0, function ()
{
  out('all is done');
});

Using promises:

function out(msg)
{
  $('#output').append(msg + '<br>');
}

var myDeferred = [];
$.each([8, 3, 4, 6, 9, 15, 7, 1], function (index, time)
{
  myDeferred.push($.Deferred(function(dfd)
  {
    var f = function() {
      out(time);
      dfd.resolve();
    }
    if (index > 0)
      myDeferred[index - 1].done(function() { setTimeout(f, time * 1000); });
    else 
      setTimeout(f, time * 1000);
  }).promise());
});

$.when.apply($, myDeferred).then(function ()
{
  out('all is done');
});
JuniorCompressor
  • 19,631
  • 4
  • 30
  • 57
  • 3
    defeats the purpose of trying to use promises which seems to be what OP is trying to grasp. In an ajax situation there is no guarantee that data would be returned in same order as requests are made – charlietfl Feb 15 '15 at 13:37
  • also , this solution requires prior process to have completed before new one is initiated, takes far longer that way – charlietfl Feb 15 '15 at 13:43
  • 1
    Yes but I think is what @dtcSearch asks – JuniorCompressor Feb 15 '15 at 13:44
  • this is my answser, just, @JuniorCompressor more close of my demo ? Is possible ? – dtcSearch Feb 15 '15 at 14:00
  • @charlietfl it's not a speed problem, it's a demo code, i've use it in case of indexedDB multi-insert (for not block the client browser with multi-insert at the same time) – dtcSearch Feb 15 '15 at 14:01
2

Instead of logging your response within the initial loop, pass your data to resolve() then inside when() you will receive the array of resolved data. Loop over that array instead and all will be in order

var myDeferred = [];
$.each([8, 3, 4, 6, 9, 15, 7, 1], function (index, time)
{
  myDeferred.push($.Deferred(function(dfd)
  {
    setTimeout(function ()
    {
      /* pass data to resolve()*/
      dfd.resolve(time);
    }, time * 100);
  }).promise());
});

$.when.apply($, myDeferred).then(function ()
{
    /* loop over arguments */
    $.each(arguments,function(_, time){
        out(time);
    });
    console.log(arguments);
    out('all is done');
});

DEMO

charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • I want callbacks on array myDeferred not called at the same time, here, it's just the result in the right order, but I speak more about the way to do that. thanks for this demo, you resolve (with arguments) an other of my problem but not this one – dtcSearch Feb 15 '15 at 13:55
  • so based on start time 0 , what exactly do you want to have happen? – charlietfl Feb 15 '15 at 13:58