需要帮助来了解Promise.all和异步

时间:2020-02-13 15:53:53

标签: javascript node.js promise

这是我要讨论的代码。

view: async (req, res, next) => {  
        let formato = req.query.formato || 'details';
        try {
            let mode = Client.getMode(formato);

            let options = {
                columns: mode.columns,
                withRelated: mode.withRelated,
            };
            let client_promises = [ ]

            req.query['ids'].map( id => {

                let client =  Client.findById(id, options);
                client_promises.push(client)

            })

            let response = await Promise.all(cliente_promesas)

            return res.json({ success: true, data: response });
        } catch (error) {
            return next(error);
        }
    },

我了解到.map函数在id数组上进行迭代,然后将其传递给Client.findById,以便它可以返回要兑现的承诺,并在解决时获取客户端的数据。

现在,这些承诺被推送到一个数组中,然后被传递给Promise.all,但是我真的不明白在哪里正在解决它们。当数组中的所有承诺都已解决时,Promise.all是否只是传递了已解决的承诺?

我也了解await只是让代码在继续之前等待了诺言的解决。 但是client_promises中的承诺在哪里得到解决? 我知道这是基本知识,但对于我自己的一生,我似乎无法阅读足够的手册和指南来理解这一点。

3 个答案:

答案 0 :(得分:2)

所有Promise.all要做的是等待数组中传递给它的每个Promise完成。它不会“解雇”他们。实际上,传递的数组中的每个Promise甚至可能都处于已解决状态。从创建之初起,Promise就很“热”。

以您的示例为例,通过id获取项的功能会立即启动,并且同步返回一个Promise,该承诺最终将解析为通过id检索的任何对象。这很关键:Promise的返回不是不是异步部分,而是解决方案。

Promise.all将所有诺言变成一个诺言。

请考虑以下示例。我使用3个id并完全按照您的方式做,我称findById并将函数(一个Promise)返回的内容放入数组promises中。在findById中,我还添加了一个 extra .then调用,以演示这些承诺是“热”的,而不是等待Promise.all调用的。另外请注意,我仍然返回p

到我们实际到达Promise.all时,promises中的所有Promise都已经解决,这就是为什么您看到它们首先打印到控制台的原因。它们都需要100-600毫秒才能解决,但是我们会主动等待整整1000毫秒,然后再调用Promise.all

不幸的是,没有(某种)API使用本机实现来显示Promise的状态。我认为曾经有一些使用诸如Bluebird和jQuery之类的用户土地库的方法,但是没有关于浏览器如何实现的方法。否则,我们可以在致电Promise.all之前检查Promise,以查看它们是否已解决或待处理。

/**
 * Utility function to wait a duration before resolving
 * @param {number} [delay=100] How long to wait
 * @returns {Promise<undfined>} Promise that will resolve after delay
 */
function timeout(delay = 100) {
  return new Promise(resolve => {
    setTimeout(resolve, delay);
  });
}

/**
 * Simulated find function that returns an object
 * @param {number} id The id of the object to get
 * @returns {Promise<object>} The fake DB object
 */
async function findById(id) {
  await timeout((Math.random() * 500) + 100);
  return {
    id,
    data: `foo-${id}`
  };
}

(async function() {
  const idsToGet = [1, 2, 3];
  const promises = idsToGet.map(id => {
    // Call to get the object
    const p = findById(id);

    // Let's add another listener here to know when they are done
    p.then(r => {
      console.log(`${r.id} is done`);
    });

    // Still return the actual Promise created by findById
    return p;
  });

  // Just for kicks
  await timeout(1000);

  // Wait for EVERYTHING to be done
  const res = await Promise.all(promises);

  console.log(JSON.stringify(res, null, 4));
}());

答案 1 :(得分:0)

Promise.all()获取未解决的Promise的列表/数组。 就像是一个很大的 promise (承诺),它接受了所有未解决的承诺,直到所有承诺都得到解决,Promise.all()才被解决。

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});

在上面的示例中,您可以看到我们向Promise.all()传递了3个Promise 而当所有条件都满足时,只会触发。然后

在您的情况下:

 Client.findById(id, options);

必须返回要推送到client_promises数组中的Promise对象。 然后将它们提供给Promise.all(),直到这一点,您的承诺只是他们没有解决的承诺。

promise.all还会返回一个承诺,就像您在它前面一样等待。 它会等到他们解决后再给您一系列已解决的承诺。

答案 2 :(得分:0)

当您执行let client = Client.findById(id, options);时,承诺实际上是“被解雇的” (即代码开始运行)。 await Promise.all然后等待所有问题都解决,或者其中一个被拒绝,在这种情况下Promise.all也会以第一个promise拒绝的值被拒绝。