2

I've been puzzling for quite a while trying to wrap my head around JavaScript promises. I want to fix some issues with asynchroneous calls in my code, to de-spagethise it. But I'd love for an expert to help me, because I've wasted quite some time already.

I want to use the jQuery Deferreds for it, since I'm using jQuery (v1.11) in my project already, and I don't want to add any more libraries (already have over 5). I read that the jQuery doesn't fully follow the Promises/A spec, but I figured it'd be good enough for my use case. I'll look at q.js or other libs later.

I was trying to create a simple example and I'm already familiar with the asynchroneous behaviour of JavaScript as exemplified by this SO question: setTimeout delay not working

I created a JS fiddle to solve that user's problem but using a 'pyramid of doom' construction: http://jsfiddle.net/bartvanderwal/31p0w02b/

Now I would like a nice bare-bones example of how to flatten this pyramid using Promises and chaining method calls using then()'s or something:

$.when(takeStep())
  .then(takeStep())
  .then(takeStep())
  .then(takeStep())..

However I can't get it to work. My attempt so far is in this Fiddle: http://jsfiddle.net/bartvanderwal/vhwnj6dh/


Edit 20:58: Here is the now working fiddle thanks to (mainly) @Bergi: http://jsfiddle.net/bartvanderwal/h2gccsds/
Community
  • 1
  • 1
Bart
  • 5,065
  • 1
  • 35
  • 43

1 Answers1

2

But I can't get it to work

Some points:

  • don't use an array of deferreds, even less a global one! Break it into single steps, and use a single promise for each step.
  • use the counter value to resolve the promise. A promise should always represent an (async) result.
  • don't use $.when unless you need to wait for multiple promises
  • then does take a callback function. You must not call takeStep(), but pass it.

You also might want to have a look at this answer for rules-of-thumb to get familiar with promises.

// the most generic function that only waits and returns a promise
function wait(t, v) {
    var d = new $.Deferred();
    setTimeout(function() {
        d.resolve(v);
    }, t);
    return d.promise();
}

// logs the value and returns the next number
function markStep(nr) {
    log('step ' + cntr + ': ' + getCurrentTime() );
    return nr+1;
}
// waits before logging and returns a promise for the next number
function takeStep(nr) {
    return wait(stepTime, nr).then(markStep);
}

takeStep(0)
.then(takeStep)
.then(takeStep)
.then(takeStep)
.then(takeStep)
.done(function(nr) {
    log('done (' + getCurrentTime() + ')');
});
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks @Bergi. For the pointers, though the array of deferreds, was just an intermediary attempt to get stuff working, but all good points. I put your code into a (working) JSFiddle: [http://jsfiddle.net/bartvanderwal/h2gccsds/](http://jsfiddle.net/bartvanderwal/h2gccsds/) – Bart Dec 04 '14 at 19:48
  • Thanks, good to hear it works - I didn't make the effort to test it :-) – Bergi Dec 04 '14 at 20:07
  • It didn't work strictly, as in 'did not compile' because some functions and constants (like `stepTime`) are missing, but they only distract from the answer. Readers looking for compiling code should go to the Fiddle :). – Bart Dec 04 '14 at 20:29