代码之家  ›  专栏  ›  技术社区  ›  alfredopacino

等待循环vs.Promise.all[重复]

  •  3
  • alfredopacino  · 技术社区  · 6 年前

    await 循环对a Promise.all

    let insert = (id,value) => {
        return new Promise(function (resolve, reject) {
            connnection.query(`insert into items (id,value) VALUES (${id},"${value}")`, function (err, result) {
                if (err) return reject(err)
                    return resolve(result);
            });
        });
    };
    

    Promise.all解决方案(它需要一个for循环来构建promises数组..)

    let inserts = [];
    for (let i = 0; i < SIZE; i++) inserts.push(insert(i,"..string.."))
    Promise.all(inserts).then(values => { 
        console.log("promise all ends");
    });
    

    等待循环解

    let inserts = [];
    (async function loop() {
        for (let i = 0; i < SIZE; i++) {
            await insert(i, "..string..")
        }
        console.log("await loop ends");
    })
    

    编辑:谢谢anwsers,但我会更深入一点。 等待 循环顺序地发射请求,所以如果在中间1个请求花费更长的时间,其他的请求等待它。 这和 :如果1 req需要更长时间,则在返回所有响应之前不会执行回调。

    3 回复  |  直到 6 年前
        1
  •  11
  •   nem035    6 年前

    您使用的示例 Promise.all Promise.all(...).then(thisCallback) 只有在所有请求都成功时才会触发。

    注:承诺从 我保证 将在给定数组中的一个承诺被拒绝时立即拒绝。

    const SIZE = 5;
    const insert = i => new Promise(resolve => {
      console.log(`started inserting ${i}`);
      setTimeout(() => {
        console.log(`inserted ${i}`);
        resolve();
      }, 300);
    });
    
    // your code
    let inserts = [];
    for (let i = 0; i < SIZE; i++) inserts.push(insert(i, "..string.."))
    Promise.all(inserts).then(values => {
      console.log("promise all ends");
    });
    
    // requests are made concurrently
    
    // output
    // started inserting 0
    // started inserting 1
    // started inserting 2
    // ...
    // started inserting 4
    // inserted 0
    // inserted 1
    // ...
    // promise all ends

    注意:使用时可能更干净 .map

    Promise.all(
      Array.from(Array(SIZE)).map((_, i) => insert(i,"..string.."))
    ).then(values => { 
        console.log("promise all ends");
    });
    

    您使用的示例 await 另一方面,在继续并触发下一个承诺之前,等待每个承诺得到解决:

    const SIZE = 5;
    const insert = i => new Promise(resolve => {
      console.log(`started inserting ${i}`);
      setTimeout(() => {
        console.log(`inserted ${i}`);
        resolve();
      }, 300);
    });
    
    let inserts = [];
    (async function loop() {
      for (let i = 0; i < SIZE; i++) {
        await insert(i, "..string..")
      }
      console.log("await loop ends");
    })()
    
    // no request is made until the previous one is finished
    
    // output
    // started inserting 0
    // inserted 0
    // started inserting 1
    // ...
    // started inserting 4
    // inserted 4
    // await loop ends

    就复杂性而言,第一个示例的时间复杂性等于 O(longestRequestTime)

    另一方面 例如 O(sumOfAllRequestTimes) 因为无论单个请求需要多长时间,每个请求都必须等待前一个请求完成,因此总时间将始终包括所有请求。

    为了计算出数字,忽略由于运行代码的环境和应用程序而导致的所有其他潜在延迟,对于1000个请求,每个请求需要1s,则 我保证 示例仍然需要~1s,而 等待 例如,大约需要1000秒。

    time comparison chart

    注: 我保证 实际上不会完全并行地运行请求,一般来说,性能将在很大程度上取决于代码运行的确切环境及其状态(例如事件循环),但这是一个很好的近似值。

        2
  •  5
  •   traktor    6 年前

    这两种方法的主要区别在于

    1. 这个 await 版本在循环中按顺序发出服务器请求。如果其中一个错误未被捕获,则不会发出更多请求。如果使用try/catch块捕获请求错误,则可以识别失败的请求,并可能以某种形式恢复代码,甚至重试该操作。

    2. 这个 Promise.all maximum number of concurrent requests 被允许如果其中一个请求失败,则 insert 函数)创建承诺数组时。

    如另一份答复所述, 是非阻塞的,并返回事件循环,直到其操作数承诺得到解决。两者 我保证 等待

        3
  •  2
  •   Ashish Mukarne    6 年前

    每一个都有不同的优势,我们需要哪一个来解决我们的问题。

    for(let i = 0;i < SIZE; i++){
        await promiseCall();
    }
    

    在ES2018中,它对某些情况进行了简化,例如,如果您只想在第一次迭代完成时调用第二次迭代,请参考以下示例。

    async function printFiles () {
      const files = await getFilePaths()
    
      for await (const file of fs.readFile(file, 'utf8')) {
        console.log(contents)
      }
    }
    

    答应我

    var p1 = Promise.resolve(32);
    var p2 = 123;
    var p3 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("foo");
      }, 100);
    });
    Promise.all([p1, p2, p3]).then(values => { 
      console.log(values); // [32, 123, "foo"]
    });
    

    这将按顺序执行每个承诺,并最终返回组合的旋转值数组。

    如果这些承诺中的任何一个被拒绝,它将只返回被拒绝承诺的值。遵循以下示例:,

    var p1 = Promise.resolve(32);
    var p2 = Promise.resolve(123);
    var p3 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("foo");
      }, 100);
    });
    Promise.all([p1, p2, p3]).then(values => { 
      console.log(values); // 123
    });