【问题标题】:Wait for asynchronous calls to complete and return等待异步调用完成并返回
【发布时间】:2020-01-02 06:40:29
【问题描述】:

我需要在 nodejs 中编写一些云函数。这个特定的 Cloud Function 需要遍历 URL 数组并对第三方 API 进行一些异步调用。

这是一些模拟我正在尝试做的占位符代码,改编自here

function checkPhotos(photos) {
  var checkedPhotos = [];
  var promiseArray = photos.map(asyncFunction);

  Promise.all(promiseArray).then(results => {
    console.log('results are: ', results)
    results.forEach(result => { checkedPhotos.push(result) });
  })

  // I want to block here until the Promise.all call above completes
  // but it does not block, it returns [] immediately while the async
  // calls run
  return checkedPhotos;
}

// This is a pretend async function to simulate the third party API
function asyncFunction(photo) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("in async function, photo is " + photo)
      resolve(photo)
    }, Math.random()*2000)
  })
}

然后我调用函数:

var photos = ['https://example.com/example.jpg', 'https://example.com/example2.jpg'];
var checkedPhotos = checkPhotos(photos);

我希望checkedPhotos 包含来自results 的值,但起初它是一个空数组,然后异步调用完成并填充数组。如何使 checkPhotos() 阻塞,直到所有异步调用都完成,以便我可以将 checkedPhotos 作为完全填充的数组返回?

【问题讨论】:

  • 您不会在 Javascript 中“阻止”。您将需要结果的代码放在异步回调中。这就是数据可用的地方。有了 Promise,你还可以使用 asyncawait 来编写看起来更同步的代码,尽管它仍然不是真正的阻塞。
  • 这就是你正确使用 Promise 的方式 - pastebin.com/rNQrS1x5
  • 关于 javascript 中的任何异步,您需要了解的主要内容是……您不能“短路”代码以提供同步结果……对于承诺,您必须使用 @987654331 @ 获取结果...或使用 async/await 语法

标签: javascript node.js asynchronous


【解决方案1】:

我建议只返回Promise.all,因为你没有在函数内部做任何事情。如果您想执行任何操作,请使用 async/await 等待结果。

async function checkPhotos(photos) {
    var checkedPhotos = [];
    var promiseArray = photos.map(asyncFunction);

    const results = await Promise.all(promiseArray);
    console.log('results are: ', results)
    results.forEach(result => { checkedPhotos.push(result) });
    // Some other action
    return checkedPhotos;
}

没有动作

function checkPhotos(photos) {
  var promiseArray = photos.map(asyncFunction);
  return Promise.all(promiseArray);
}

async function somefunc(){
    await checkPhotos(photos);
} 

【讨论】:

  • 你能检查this的问题吗,拜托!
【解决方案2】:

在您的示例中,您必须在 Promise.all 回调函数中返回值,因为 Promise.all 将订阅该异步调用并要求数据库引擎在完成后运行回调函数。此外,您还需要订阅Promise.all.the(cb).catch(cb) 中的 catch 函数并传递回调函数 Incas 的错误也会返回一些内容。

另一种等待所有承诺完成的方法,你必须使用 async 和 await 关键字,只需在 function checkPhotos(... 之前添加 async 关键字和在 Promise.all... 之前添加广告 await 关键字,这将告诉 js 引擎当您收到响应时,您需要在等待行下面运行代码。

如果您从另一个函数调用此函数,则需要其他函数来等待解决此问题,您可以简单地使用上层异步等待解决方案并在调用时订阅此函数回调,如下所示。

 function other () {
  checkPhotos(photos).then(cb);
 }

   async function checkPhotos(photos) {
     .....
      await Promise.all(....then()..)
         // Do some stuff
        return checkedPhotos
       }

这就是 js 处理异步调用的方式,它不会阻塞你的代码(事件循环),它只是允许你订阅一个异步调用并传递一个回调函数,以便在 JavaScript 得到响应后执行。

【讨论】:

  • 是的,offcours,我知道它区分大小写,只是拼写错误,谢谢。
  • 好吧,我没想到,只是因为你打错了 5 次……但现在一切都好了。我撤回了我的反对票。
【解决方案3】:

为什么不使用异步等待?

async function checkPhotos(photos) {
  var checkedPhotos = [];

  for (const photo of photos) {
    let result = await asyncFunction(photo);
    checkedPhotos.push(result);
  }

  return checkedPhotos;
}

然后这样称呼它:

var photos = ['https://example.com/example.jpg', 'https://example.com/example2.jpg'];
checkPhotos(photos)
.then(checkedPhotos => {
  // do something
})

【讨论】:

  • 现在此代码返回 undefined - 这比问题中的代码更糟糕
  • 我认为 promise.all 比循环更好,promise.all 将并行触发所有异步调用并等待它,您的解决方案将在发送异步请求之前等待每个调用,这也会导致延迟很多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 1970-01-01
  • 2021-11-13
相关资源
最近更新 更多