如何等待异步函数执行?
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“异步”函数的主体中没有“等待”,它会以任何不同的方式执行吗? [复制]