Home > Blockchain >  Synchronous Promise Chaining
Synchronous Promise Chaining

Time:09-25

I'm trying to understand promise chaining and I'm under the impression the following code should run synchronously since I chained the 'then' statements. Why does it run asynchronously for the 2nd and 3rd data fetches.

console.log("Start Program")
console.log("Start Getting Data 1")

new Promise((succes) => {
    setTimeout(()=>{
        console.log("Got Data 1")
        succes()},3000)
    }
).then(()=>{
    console.log("Start Getting Data 2")
    setTimeout(()=>{console.log("Got Data 2")},3000)
}).then(()=>{
    console.log("Start Getting Data 3")
    setTimeout(()=>{console.log("Got Data 3")},3000)
})

console.log("End Program")

CodePudding user response:

It's because you're not returning a Promise from the second. So, basically, after finishing first, the next 2 functions are triggered.

If you want that 3 wait for 2 have to do:

console.log("Start Program")
console.log("Start Getting Data 1")

new Promise((succes) => {
    setTimeout(()=>{
        console.log("Got Data 1")
        succes()},3000)
    }
).then(()=>{   
     console.log("Start Getting Data 2")
 return new Promise((succes) => {
    setTimeout(()=>{
        console.log("Got Data 2")
        succes()},3000)
    }
)
}).then(()=>{
    console.log("Start Getting Data 3")
    setTimeout(()=>{console.log("Got Data 3")},3000)
})

CodePudding user response:

To solve your problem you need to return a new promise from the then() handler. Otherwise the next then() handler will execute immediately after the former.

).then(()=>{
    console.log("Start Getting Data 2")
    setTimeout(()=>{console.log("Got Data 2")},3000)
    // no promise is returned, next then handler will execute
    // immediately
}).then(()=>{

To simplify the promise creation in combination with setTimeout MDN suggest wrapping it at the lowest possible level. Creating a helper function that does nothing other than wrapping the old callback function inside a promise.

Creating a Promise around an old callback API

A Promise can be created from scratch using its constructor. This should be needed only to wrap old APIs.

In an ideal world, all asynchronous functions would already return promises. Unfortunately, some APIs still expect success and/or failure callbacks to be passed in the old way. The most obvious example is the setTimeout() function:

setTimeout(() => saySomething("10 seconds passed"), 10*1000);

Mixing old-style callbacks and promises is problematic. If saySomething() fails or contains a programming error, nothing catches it. setTimeout is to blame for this.

Luckily we can wrap setTimeout in a promise. Best practice is to wrap problematic functions at the lowest possible level, and then never call them directly again:

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

wait(10*1000).then(() => saySomething("10 seconds")).catch(failureCallback);

Basically, the promise constructor takes an executor function that lets us resolve or reject a promise manually. Since setTimeout() doesn't really fail, we left out reject in this case.

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

console.log("Start Program")
console.log("Start Getting Data 1")

wait(3000)
.then(() => {
  console.log("Got Data 1");
  // By not returning the next `then()` handler will be
  // executed immediately.
})
.then(() => {
  console.log("Start Getting Data 2");
  // Return a new promise so the next `then()` handler is
  // not immediately executed.
  return wait(3000);
})
.then(() => {
  console.log("Got Data 2");
})
.then(() => {
  console.log("Start Getting Data 3");
  return wait(3000); // <- return promise so next `then` waits
})
.then(() => {
  console.log("Got Data 3");
});

The above could be condensed by combining some of the "Got Data" and "Start Getting Data" console logs.

  • Related