Search code examples
javascriptnode.jspromise

I have no idea why setTimeout wrapping promise not working as i expected


I have this code.

const testArray = [1, 2, 3, 4, 5];

const test = async () => {
    return Promise.resolve().then(() => {
        console.log("Testing console log: ", new Date());
    });
};

const testPromises = testArray.map(async (value) =>
    new Promise((resolve) => setTimeout(resolve, 2000)).then(() => test())
);

const testResult = testPromises.reduce(
    (p, testPromise) => p.then(() => testPromise),
    Promise.resolve()
);

So i expected resolve promises made with testArray map function sequentially with setTimeout worked and log the messsage with 2 seconds interval.

but it is logging at the same time.

I have no idea why this is not working.


Solution

  • The issue is with your testPromises. It creates 5 promises that resolve after 2 seconds simultaneously upon the declaration. When they are declared, the setTimeout countdowns are already ticking.

    const testPromises = testArray.map(async (value) =>
        new Promise((resolve) => setTimeout(resolve, 2000)).then(() => test())
    );
    
    [Promise, Promise, Promise, Promise, Promise]
    

    What you actually want is to create functions that return a Promise using the map function, so the countdown only ticks when it is called.

    const testPromises = testArray.map((value) =>
        () => new Promise((resolve) => setTimeout(resolve, 2000)).then(() => test())
    );
    
    [() => Promise, () => Promise, () => Promise, () => Promise, () => Promise]
    

    and then call that function to create the Promise in the reduce sequence:

    const testResult = testPromises.reduce(
        (p, testPromise) => p.then(() => testPromise()),
        Promise.resolve()
    );
    

    Here's the full code:

    const testArray = [1, 2, 3, 4, 5];
    
    // no need to use async when it returns a Promise explicitly
    const test = () => {
      return Promise.resolve().then(() => {
        console.log("Testing console log: ", new Date());
      });
    };
    
    // map into a funtion that returns a Promise instead
    const testPromises = testArray.map((value) =>
      () => new Promise((resolve) => setTimeout(resolve, 2000)).then(() => test())
    );
    
    
    // when chaining on the Promise using reduce function, call the testPromise() function to create the Promise that resolves after 2 seconds on the fly
    const testResult = testPromises.reduce(
      (p, testPromise) => p.then(() => testPromise()),
      Promise.resolve()
    );