Gazzer
Gazzer

Reputation: 4646

How do I handle Promises across multiple functions?

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);
    });   
});

Upvotes: 0

Views: 636

Answers (1)

Bergi
Bergi

Reputation: 664538

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);
    });   
});

Upvotes: 2

Related Questions