【问题标题】: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 请求并更新数据。但是在这里我很困惑如何做到这一点。

标签: javascript node.js


【解决方案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

  1. npm install request-promise
  2. 如下实现 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/…
猜你喜欢
  • 1970-01-01
  • 2017-12-30
  • 1970-01-01
  • 2018-09-29
  • 2018-10-23
  • 2019-11-07
  • 1970-01-01
  • 2023-01-20
相关资源
最近更新 更多