Promise.all

时间:2019-07-16 12:41:48

标签: javascript promise async-await

我有此代码段,应await 5个承诺,暂停2秒,然后继续await另外5个。但是,输出显示未等待两个Promise.all尽管当我尝试在Promise中返回值时,它会正确返回。我是否理解Promise.all的概念错误,或者我的代码中缺少某些内容?

(function () {
    let val = 0

    const promiseArr = []
    for (let i = 0; i < 10; i++) {
        promiseArr[i] = new Promise((res) => {
            val += 500
            setTimeout((val2) => {
                console.log(val2)
                res()
            }, val, val)
        })
    }

    console.log();
    (async function() {
        await Promise.all(promiseArr.slice(0, 5))
        console.log('start await')
        await new Promise((res) => setTimeout(res, 2000))
        console.log('done await')
        await Promise.all(promiseArr.slice(6, 10))
    })()
}) ()

预期输出:

500
...
2500
start await
done await
3000
...
5000

实际输出:

500
1000
1500
2000
2500
start await
3000
3500
4000
4500
done await
5000

编辑: 现在我明白了为什么会这样。似乎我对Promises误解了一个基本概念。谢谢你们的帮助!

3 个答案:

答案 0 :(得分:2)

您之所以会看到这种情况,是因为承诺创建后即开始(或者,无论如何,当前同步块完成时)就开始运行,而不是await被启用时开始。

稍微整理一下代码,为每个事件打印时间戳可能会启发您:

const t0 = +new Date();

const logWithTime = (message = "") =>
  console.log("" + Math.round(+new Date() - t0) + ": " + message);

(async function() {
  let val = 0;

  const resolver = res => {
    val += 500;
    const thisVal = val; // so we have a binding for the effective value
    logWithTime("Creating timeout for " + thisVal);
    setTimeout(
      arg => {
        logWithTime("Timeout for " + thisVal);
        res();
      },
      thisVal,
      thisVal,
    );
  };

  const promiseArr = [];
  for (let i = 0; i < 10; i++) {
    promiseArr[i] = new Promise(resolver);
  }

  logWithTime("awaiting for first 5...");
  await Promise.all(promiseArr.slice(0, 5));
  logWithTime("waiting for 2 seconds...");
  await new Promise(res => setTimeout(res, 2000));
  logWithTime("waiting for the rest...");
  await Promise.all(promiseArr.slice(6, 10));
  logWithTime("all done");
})();

打印

0: Creating timeout for 500
10: Creating timeout for 1000
10: Creating timeout for 1500
10: Creating timeout for 2000
10: Creating timeout for 2500
10: Creating timeout for 3000
10: Creating timeout for 3500
10: Creating timeout for 4000
10: Creating timeout for 4500
10: Creating timeout for 5000
10: awaiting for first 5...
511: Timeout for 500
1011: Timeout for 1000
1515: Timeout for 1500
2013: Timeout for 2000
2510: Timeout for 2500
2511: waiting for 2 seconds...
3010: Timeout for 3000
3512: Timeout for 3500
4011: Timeout for 4000
4511: Timeout for 4500
4511: waiting for the rest...
5011: Timeout for 5000
5011: all done

(或大约,取决于事物)。

您可以在那里查看解决超时的顺序。

答案 1 :(得分:1)

当您致电setTimeout时,您的计时器开始计时,而当您await履行其诺言时,不是

运行(res) => setTimeout(res, 2000)时,您有4个先前的setTimeouts完成并在解决之前调用console.log

答案 2 :(得分:0)

我也偶然发现了这种误解:当您定义Promise时,它的功能即在该时刻执行。如果我了解您要执行的操作,则需要定义一个函数数组,并根据需要调用它们。

(function () {
    let val = 0

    const promiseArr = []
    for (let i = 0; i < 10; i++) {
        promiseArr[i] = () => new Promise((res) => {
            val += 500
            setTimeout((val2) => {
                console.log(val2)
                res()
            }, val, val)
        })
    }

    console.log();
    (async function() {
        await Promise.all(promiseArr.slice(0, 5).map((fn) => fn()))
        console.log('start await')
        await new Promise((res) => setTimeout(res, 2000))
        console.log('done await')
        await Promise.all(promiseArr.slice(6, 10).map((fn) => fn()))
    })()
}) ()