如何等待异步函数执行?

Posted

技术标签:

【中文标题】如何等待异步函数执行?【英文标题】:How to wait for asynchronous function to be executed? 【发布时间】:2019-12-30 00:30:27 【问题描述】:

我正在从不同的 http 请求中获取板球比赛和得分。第一个获取匹配列表(具有唯一 ID),第二个获取使用唯一 ID 的分数。我需要完成第二个 http 请求(data.map 函数),然后发送数据变量值(在 res.json 中不使用超时)。我知道使用 Promises/Callbacks,但我对代码感到困惑。目前使用 setTimeout 等待,但我不想使用超时。请帮忙。

app.get('/api/matches', (req, res) => 
    let url = `http://cricapi.com/api/matches?apikey=$key`
    request(url,  json: true , (err, resp, body) => 
        if (err) return res.json(
            error: 1,
            msg: err,
        )
        let data = body.matches.filter(match => 
            return match.matchStarted
        )

        data.map((element, index) => 
            let requrl = `http://cricapi.com/api/cricketScore?apikey=$key&unique_id=$element.unique_id`
            request(requrl,  json: true , (err, resp, body) => 
                element.score = body.score
                data.push(element)
            )
        )

        setTimeout(()=>
            res.json(
                error: 0,
                matches: data
            )  
        ,2000)
    )
)

期望输出与他们的分数匹配,但没有超时功能,当前输出未定义。

【问题讨论】:

你使用的是哪个请求库? 你能在这里分享一下密钥吗?需要测试一种方法。您可以稍后重新生成它。 Nodejs 请求是我正在使用的;这个:npmjs.com/package/request 很抱歉,我无法共享密钥。执行此代码时,分数会显示在网页中,但使用超时功能等待数据更新。但是使用 Promises,将执行第二个 http 请求并更新数据。但是在这里我很困惑如何做到这一点。 【参考方案1】:

尝试像这样将 map 包装在 promise 中。


app.get('/api/matches', (req, res) => 
    let url = `http://cricapi.com/api/matches?apikey=$key`
    request(url,  json: true , (err, resp, body) => 
        if (err) return res.json(
            error: 1,
            msg: err,
        )
        let data = body.matches.filter(match => 
            return match.matchStarted
        )

        let newData = data.map((element, index) => 
            return new Promise((resolve, reject) => 
                let requrl = `http://cricapi.com/api/cricketScore?apikey=$key&unique_id=$element.unique_id`
                request(requrl,  json: true , (err, resp, body) => 
                    element.score = body.score
                    resolve(element);
                )
            );

        )


        Promise.all(newData).then(data => 
            res.json(
                error: 0,
                matches: data
            )
        )


    )
)

【讨论】:

非常感谢。效果和我预期的一样好。 我认为 request-promise 和 async/await 比接受的答案要好得多 我认为 request-promise 做同样的事情【参考方案2】:

你应该使用async/await来等待你的请求完成,所以你可以做的是,所以你需要使用支持promise的request-promise包,这样你就可以使用async await,见他们的documentation here

    npm install request-promise 如下实现 async/await
const request = require('request-promise');

app.get('/api/matches', async (req, res) => 
  let url = `http://cricapi.com/api/matches?apikey=$key`
  let  response, body  = await request( uri: url, method: 'GET' )
  if (response.statusCode !== 200)
   return res.json( error: 1, msg: err,)
   

  let data = body.matches.filter(match => 
         return match.matchStarted
  )
  await Promise.all(data.map(async (element, index) => 
    let  response, body  = await request( uri: url, method: 'GET' )
    element.score = body.score
    data.push(element)
  ))
  return res.json( error: 0, matches: data )


【讨论】:

我认为 requrl 行丢失了,尽管我理解它。我会执行并告诉你输出。 这不起作用,因为await 不在async 函数中,因此是语法错误。更重要的是,request.get 是否返回Promise?如果没有,这也不会因为这个原因起作用。 我更新了答案,在data.map回调函数中添加了异步,然后就可以了 @lonesomeday 是的 request.get 返回承诺,见the documentation @onuriltan 不,不会。 See my answer to this question,这是完全相同的问题。【参考方案3】:

将每个请求包装在 Promise 中并将它们链接起来。

伪代码:

// Promise for match
const getMatch = new Promise((resolve, reject) => 
    // Do request, call resolve (or reject) when completed.
    request(url, resolve);
); 


// Promise for score
const getScore(id) = new Promise((resolve, reject) => 
    // Do request, call resolve (or reject) when completed.
    request(url, resolve);
); 

// Chain promises
getMatch()
    .then(match => getScore(match))
    .then(profit => console.log(profit)
    .catch(error => console.warn(error)

【讨论】:

但是在匹配列表的http请求里面,只有这样我才会得到唯一的id,里面同样是score的http请求,所以做出不同的promise会处理吗? Promise 只不过是异步代码的包装器,可以将回调附加到它。我的示例 getScore() 将在 getMatch() 返回时调用(作为参数传递给它的解析函数)。当 getScore() 完成时,结果将记录到控制台。将其他零碎的东西放在适当的位置取决于您。请看:developer.mozilla.org/nl/docs/Web/javascript/Reference/…

以上是关于如何等待异步函数执行?的主要内容,如果未能解决你的问题,请参考以下文章

等待两个异步完成函数完成,然后再执行下一行代码

如果javascript“异步”函数的主体中没有“等待”,它会以任何不同的方式执行吗? [复制]

在构造函数或 ngOnInit 中加载异步函数

在映射下一项之前,异步等待映射不等待异步函数在映射函数内部完成

python实现异步调用函数执行

在python中等待多个异步函数