简体   繁体   中英

Node.js Promise chain resolving too early

There's something about chaining promises that I don't understand. The Node.js snippet below produces the following output. Why is promise.allSettled called after the first sleep on line 18 and not after the 2nd one on line 21?

Cycle 0 is going to sleep     promise.js:2
Cycle 0 slept for 2 seconds   promise.js:6
Returned from sleep function  promise.js:19
Cycle 0 is going to sleep     promise.js:2
Done with the process         promise.js:27
Cycle 0 slept for 2 seconds   promise.js:6

 function sleep(cycle) { console.log(`Cycle ${ cycle } is going to sleep`); return new Promise(resolve => { setTimeout(() => { console.log(`Cycle ${ cycle } slept for 2 seconds`); resolve(); }, 2000); }); } function process() { let cycles = 1; let subprocesses = []; for (let i = 0; i < cycles; i++) { subprocesses.push( sleep(i).then(() => { console.log('Returned from sleep function'); sleep(i); }) ); } Promise.allSettled(subprocesses).then(results => { console.log('Done with the process'); }); } process();

Because you haven't resolved the promise created sleep(i).then to the promise from the second sleep , so it doesn't wait for that second operation to finish before settling. You need a return in front of the second call:

 function sleep(cycle) { console.log(`Cycle ${ cycle } is going to sleep`); return new Promise(resolve => { setTimeout(() => { console.log(`Cycle ${ cycle } slept for 2 seconds`); resolve(); }, 2000); }); } function process() { let cycles = 1; let subprocesses = []; for (let i = 0; i < cycles; i++) { subprocesses.push( sleep(i).then(() => { console.log('Returned from sleep function'); return sleep(i); // <============================ }) ); } Promise.allSettled(subprocesses).then(results => { console.log('Done with the process'); }); } process();

Here's a version with two cycles, and with the sleep calls more clearly marked:

 function sleep(cycle, sub) { console.log(`Cycle ${cycle}(${sub}) is going to sleep`); return new Promise(resolve => { setTimeout(() => { console.log(`Cycle ${cycle}(${sub}) slept for 2 seconds`); resolve(); }, 2000); }); } function process() { let cycles = 2; let subprocesses = []; for (let i = 0; i < cycles; i++) { subprocesses.push( sleep(i, "a").then(() => { console.log(`Returned from sleep function (${i})`); return sleep(i, "b"); // <============================ }) ); } Promise.allSettled(subprocesses).then(results => { console.log('Done with the process'); }); } process();

It might be clearer to split that sleep , sleep serial operation off into its own function, perhaps an async function:

async function twoSleep(i) {
    await sleep(i, "a");
    console.log(`Returned from sleep function (${i})`);
    await sleep(i, "b");
}

function process() {
    let cycles       = 2;
    let subprocesses = [];

    for (let i = 0; i < cycles; i++) {
        subprocesses.push(twoSleep(i));
    }

    Promise.allSettled(subprocesses).then(results => {
        console.log('Done with the process');
    });
}

 function sleep(cycle, sub) { console.log(`Cycle ${cycle}(${sub}) is going to sleep`); return new Promise(resolve => { setTimeout(() => { console.log(`Cycle ${cycle}(${sub}) slept for 2 seconds`); resolve(); }, 2000); }); } async function twoSleep(i) { await sleep(i, "a"); console.log(`Returned from sleep function (${i})`); await sleep(i, "b"); } function process() { let cycles = 2; let subprocesses = []; for (let i = 0; i < cycles; i++) { subprocesses.push(twoSleep(i)); } Promise.allSettled(subprocesses).then(results => { console.log('Done with the process'); }); } process();

The issue is that Promise.allSettled runs all promises in parallel, so all of them resolve at the same time. If you want to run them one by one try

async function process() {
  const cycles = 1;

  for (let i = 0; i < cycles; i++) {
    await sleep(i).then(() => {
      console.log("Returned from sleep function");
      return sleep(i);
    });
  }

  console.log("Done with the process");
}

process();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM