0

In the example below I have a function that calls another function (which in reality may call a further function or make an Ajax request).

The example works for deferring the first function but I have no idea how to make it resolve other functions that it may call.

Do I have to pass these deferred objects around to the other functions, or is there a more elegant way around this? (In reality, I'm dealing with speech synthesis using the API callbacks so the basic structure in the example can't be changed so much).

Fiddle here https://jsfiddle.net/macgroover/ahz46rw1/

function slowCount(numbers, deferred) {
  if (deferred) {
    this.deferred = jQuery.Deferred();
  }
  if (numbers.length) {
    var number = numbers.shift();
    log('SC:' + number);
    setTimeout(function() {
      doSomething(number);
      slowCount(numbers);
    }, 500);

    return this.deferred.promise();
  } else {
    this.deferred.resolveWith(this, ['resolveWith']);
    //this.deferred.resolve();
    return;
  }
}

function doSomething(number) {

  setTimeout(function() {
    log("DS:" + number);
  }, 1000);
}

$(function() {  
    $.when(slowCount([1, 2, 3, 4], true)).done(function(rslt) {
      log("All tasks finished with " + rslt);
    });   
});
Gazzer
  • 4,524
  • 10
  • 39
  • 49
  • 3
    You never ever should need to pass deferreds around. Just *always* `return` promises, and chain them using `then`. – Bergi Mar 31 '16 at 09:52
  • ^ I'm happy to hear that. Could you update the code above to work then? (These aren't sequential functions. It's a function called by another function). – Gazzer Mar 31 '16 at 09:58

1 Answers1

2

Have a look at these rules - especially, always promisify at the lowest level, which is setTimeout for you:

function wait(timeout) {
    var deferred = jQuery.Deferred();
    setTimeout(deferred.resolve, timeout);
    return deferred.promise();
}

Now the rest is fairly trivial:

function slowCount(numbers) {
    if (numbers.length) {
        var number = numbers.shift();
        log('SC:' + number);
        return wait(500).then(function() {
            return doSomething(number);
        }).then(function() {
            return slowCount(numbers);
        });
    } else {
        return $.when("end result");
    }
}

function doSomething(number) {
    // I assume you want this to be asynchronous as well
    // - so it returns a promise!
    return wait(1000).then(function() {
        log("DS:" + number);
    });
}

$(function() {  
    slowCount([1, 2, 3, 4]).then(function(rslt) {
        log("All tasks finished with " + rslt);
    });   
});
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375