skip to Main Content

I’m new to JS and I don’t understand the behaviour I see in the code snippet

const task1 = new Promise((res, rej) => {
  setTimeout(() => res('one'), 5000)
})

const task2 = new Promise((res, rej) => {
  setTimeout(() => res('two'), 5000)
})

task1
.then((x) => {                    // first then
    return Promise.resolve(task2)
})
.then((res) => {console.log(res)}) // expect to log after 10 seconds, but logs after 5 seconds

async function test() {
  try {
    const res = await task1;
    const res2 = await task2;
    console.log(res2); // also logs after 5 seconds
  } catch (error) {
    console.error(`error`);
  }
}

test();

My understanding is that the first ".then" only fires after task 1 resolves after 5 seconds,then task2 starts and resolves after another 5 seconds. However, the console logs after 5 seconds, not 10. Where have I gone wrong ?

2

Answers


  1. You need to create the second promise in the then solving block of the first (promises start executing as soon as they’re created). To fix your code so they sequentially execute as promises:

    const promiseTime = 500;
    const start = performance.timeOrigin + performance.now();
    const task = new Promise((res, rej) => {setTimeout(() => res('one'), promiseTime);});
    
    task
      .then((x)=>{
        console.log(`${x} ${(performance.timeOrigin + performance.now())-start}`);
        return new Promise((res, rej) => {setTimeout(() => res('two'), promiseTime);});
      })
      .then((x)=>{
        console.log(`${x} ${(performance.timeOrigin + performance.now())-start}`);
      });
    
    //Console output example (F12 to see, or run the snippet):
    //  one 516.677001953125
    //  two 1033.35400390625

    If you want to use async/await with promises:

    const promiseTime = 500;
    const start = performance.timeOrigin + performance.now();
    
    const res1 = await new Promise((res, rej) => {setTimeout(() => res('one'), promiseTime);});
    //Will log as soon as promise 1 is complete
    console.log(`${res1} ${(performance.timeOrigin + performance.now())-start}`);
    
    const res2 = await new Promise((res, rej) => {setTimeout(() => res('two'), promiseTime);});
    //Will log as soon as promise 2 is complete:
    console.log(`${res2} ${(performance.timeOrigin + performance.now())-start}`);
    
    //Console output example (F12 to see):
    //  one 500.010009765625
    //  two 1083.35498046875
    
    Login or Signup to reply.
  2. By creating promises as new Promise you execute them immediately so they are independent and doesn’t form any type of queue.

    To solve that you should have your tasks as functions and call them in a queue (when a promise returned by a function is resolved, call the next function).

    To run the next function you should call it inside .then() of the previous one.

    To make things easier you could use an async generator function to convert your array of promise creating functions into an async generator and use for await to iterate your promises in a queue.

    <script type="module">
    
    const task1 = () => new Promise((res, rej) => {
      setTimeout(() => res('one'), 1000)
    })
    
    const task2 = () => new Promise((res, rej) => {
      setTimeout(() => res('two'), 1000)
    })
    
    async function* queue(arr){
      for(const fn of arr){
        yield await fn();    
      }
    }
    
    // using then
    await task1().then(result => (console.log(result), task2().then(result => console.log(result))));
    
    // using await
    console.log(await task1());
    console.log(await task2());
    
    // using async generator
    for await(const result of queue([task1, task2])){
      console.log(result);
    }
    </script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search