Node.js Promise 链解决得太早

Node.js Promise chain resolving too early

关于链接承诺,我有些不明白。下面的 Node.js 片段产生以下输出。为什么 promise.allSettled 在第 18 行的第一个 sleep 之后调用,而不是在第 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();

因为您还没有将创建的承诺 sleep(i).then 解析为第二个 sleep 的承诺,所以它不会等待第二个操作完成就可以解决。您需要在第二个电话前加一个 return

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();

这是一个有两个周期的版本,睡眠调用标记得更清楚:

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();

sleepsleep 串行操作拆分成它自己的函数可能会更清楚,也许是 async 函数:

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();

问题是 Promise.allSettled 运行 所有的承诺都是并行的,所以它们都是同时解决的。如果你想运行他们一一尝试

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();