【问题标题】:How to use promise in order to wait for a function to execute如何使用 promise 来等待函数执行
【发布时间】:2021-08-25 00:57:03
【问题描述】:

我有一段异步 javascript 代码需要执行,然后可以执行下一条语句

function getEventData() {
            return new Promise(resolve => {
              eventList.forEach((event) => {
                db.collection('Events').doc(event)?.collection('registeredStudents')?.get()
                .then((querySnapshot) => {
                  eventData.push({"id": event, "number": querySnapshot.size})
                })
              })
              resolve();
            })
          }
          getEventData().then(console.log(eventData))

eventList 是一个包含 17 个元素的数组,它在数据库中列出了大约 17 次,这是低效的,但我别无选择,所以不得不这样做。无论如何,在控制台中我记录了一个空数组。我该如何解决。 PS:我是异步 javascript 和 Promise 的新手。

【问题讨论】:

  • 循环发送多个异步请求可能会导致问题。您需要使用 Promise.all(...) 之类的东西来确保所有承诺都得到履行。
  • 我对异步有点陌生。如何确保控制台日志语句在所有承诺得到解决后运行,因为.then 语句似乎不起作用
  • 我已经用一个 sn-p 更新了我的答案,它显示了你的函数应该是什么样的。

标签: javascript async-await es6-promise


【解决方案1】:

你可以使用Promise.all():

function getEventData() {
  return new Promise(async (resolve) => {
    await Promise.all(
      eventList.map(async (event) => {
        let querySnapshot = await db.collection('Events').doc(event)?.collection('registeredStudents')?.get()
        eventData.push({"id": event, "number": querySnapshot.size})
      })
    );
    resolve();
  })
}

getEventData().then(console.log(eventData))

【讨论】:

  • 我不太确定 .then 会在所有承诺解决后执行。使用后我仍然得到一个空数组。当我在地图循环中控制台登录时,我得到了我需要的东西。
  • 可能是api响应有问题。 @Vaibhav07
【解决方案2】:

这是一个关于如何在循环中使用 Promise 的简单演示。我正在执行的异步操作是“休眠”(也就是在一切都“休眠”之前什么都不会发生)..

const sleepTimes = [1, 2, 3];
const promises = [];

sleepTimes.forEach(time => {
  const promise = new Promise((resolve, reject) => {
    return setTimeout(resolve, time * 1000, time * 1000);
  });
  promises.push(promise);
});

console.log(promises);

Promise.all(promises).then((values) => {
  document.body.innerHTML = values;
});

这意味着您的函数应该类似于:

function getEventData() {
  const promises = [];
  eventList.forEach((event) => {
    // I assume this already returns a promise, so there's no need to wrap it in one
    const promise = db.collection("Events").doc(event)?.collection("registeredStudents")?.get();
    promises.push(promise);
  });
  return Promise.all(promises);
}

getEventData().then((values) => console.log(values));

【讨论】:

  • 澄清一下values 是一个刚刚由函数getEventData 返回的数组。换句话说,就是数组promises
  • 应该是每个promise返回的值的数组。
  • 好吧,据我了解,您在顶部声明的数组promises 包含来自Promise.all(promises) 行的已解决承诺。调用函数getEventData().then((value) => console.log(value)) 后,value 包含每个promises = [] 的值返回?
  • 不。数组promises 是一组未实现的承诺。它只是收集你想要实现的所有承诺。 Promise.all(promises) 将真正实现每个承诺。例如,如果您先执行const p = new Promise((res, rej) => res());,然后执行console.log(p),您会看到它只记录了一个Promise 对象。这基本上就是我们在 Promise 数组中所做的一切——从每个事件中收集 Promise 对象,然后 Promise.all() 将真正实现我们的 Promise 并返回值。 (请记住,这是高级别的)
【解决方案3】:

处理您的问题的正确方法不是使用带有 resolve 的 new Promise,而是使用 async await。 当您等待一个承诺时,它会等待它解决并返回结果(不是承诺!),然后再继续下一行。 等待 promise 的函数在调用时会返回一个 promise。 Promise.all 将多个 Promise 合并为一个,因此您可以等待多个 Promise 一次解决所有问题,并让它们同时运行(异步)。

async function getEventData(eventList) {
    try {
        const eventData = [];

        await Promise.all(eventList.map(async event => {
            const querySnapshot = await db.collection('Events').doc(event)?.collection('registeredStudents')?.get();
            eventData.push({"id": event, "number": querySnapshot.size});
        }));
        
        console.log(eventData)
    } catch (exception) {
      // error handling
    }
}

【讨论】:

  • async/await 关键字只是 Promise 的语法糖。这是完全相同的东西..
  • @MattOestreich,你的权利 - 它完全相同,但它更先进和推荐。它更短、更优雅、更易读且更易于处理。
  • 所以说问题不是使用 async/await 是一种误导。 async/await 与问题无关。
  • 因为使用了Promise.all,所以需要在某个地方生成一个promise才能得到解决。在上面的代码中,promise 是在哪里生成的?
  • get() 方法是返回承诺的方法。从这里 - db.collection('Events').doc(event)?.collection('registeredStudents')?.get();
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-18
  • 1970-01-01
  • 2020-10-11
  • 2019-12-30
  • 2023-03-21
  • 1970-01-01
相关资源
最近更新 更多