How to convert nested setTimeouts to promises

314 Views Asked by At

Using rsvp.js or any other promises/A+ implementation how can I turn code like...

console.log('step 1');
setTimeout(function() {
  console.log('step 2');
  setTimeout(function() {
    console.log('step 3');
  }, 100);
}, 300);

into a promises implementation?

4

There are 4 best solutions below

0
On BEST ANSWER

Create a delay function which returns a Promise and it actually resolves it after the specified time elapses in setTimeout, like this

function delay(time) {
    return new RSVP.Promise(function (resolve) {
        setTimeout(resolve, time);
    });
}

and then you can invoke it like this

console.log("step 1");
delay(3000)
    .then(function () {
        console.log("step 2");
        return delay(1000);
    })
    .then(function () {
        console.log("step 3");
    });
0
On

Chain the promises:

// Set up the functions which contain the promises
function step1() {
    return new RSVP.Promise(function(resolve, reject) {
        resolve();
    });
}

function step2() {
    return new RSVP.Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve();
        }, 300);
    });
}

function step3() {  
    return new RSVP.Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve();
        }, 100);
    });
}

// Now execute them:
step1()
    .then(step2)
    .then(step3)

You can read more here: http://www.toptal.com/javascript/javascript-promises

0
On

If you're okay with using q, there's a very simple solution baked into the library:

console.log('step 1');
Q.delay(300).then(function() {
    console.log('step 2');
    return Q.delay(200);
}).then(function() {
    console.log('step 3');
});
0
On

Follow the rules of thumb for promise development! First of all, we need to promisify the setTimeout calls, so that we get a function which returns us a promise for it. With the RSVP Promise constructor, it would look like this:

function delay(time) {
    return new RSVP.Promise(function(resolve) {
        setTimeout(resolve, time);
    });
}

Now, we can chain the log statements using then instead of passing the callback right into setTimeout:

console.log("step 1");
delay(3000).then(function() {
    console.log("step 2");
    return delay(1000).then(function() {
        console.log("step 3");
    });
});

…and do get back a promise for when all three steps are executed.

However, the actual feature of then is that you can unnest the callbacks now, and get exactly the same result back. So your chain would look like this:

console.log("step 1");
delay(3000).then(function() {
    console.log("step 2");
    return delay(1000);
}).then(function() {
    console.log("step 3");
});