Node.js中async fetch函数外获取存储数组及forEach场景异常问题
问题原因
- 最初的代码中,
fetchFromApi是异步函数,调用后会立即返回Promise,不会阻塞后续代码执行。调用后立刻打印failed时,fetch请求还未完成,往数组中插入值的逻辑还未触发,所以得到空数组。 - 加入
forEach后的问题,核心原因是*Array.prototype.forEach不支持等待异步回调执行完成*:你给forEach传入的async回调会被逐个启动,但forEach不会等待这些异步任务的Promise状态变更,遍历完成就直接结束函数。所以你写的await fetchFromApi(j)实际没有等待内部所有fetch请求执行完成,返回failed时所有请求还在运行中,自然还是空数组。
解决方案
提供两种常用的实现方案,可根据场景选择:
方案1:用for...of替代forEach(串行请求,可控并发)
for...of原生支持异步等待,会按顺序等待每个请求完成后再执行下一个,适合需要控制请求并发、避免触发接口限流的场景:
const myFunction = async (j) => { // 建议声明为局部变量,避免污染全局作用域 const failed = []; async function fetchFromApi(i) { const ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i const httpRequest = { method: "GET" } const response = await fetch(ApiEndpoint, httpRequest); if (!response.ok) { failed.push(i); } else { const symbolData = await response.json(); console.log(JSON.stringify(symbolData)) return JSON.stringify(symbolData); } }; // 遍历等待每个请求执行完成 for (const item of j) { await fetchFromApi(item) } return failed } myFunction(["aaa", "abc"]).then(data=>console.log(data))
方案2:用Promise.all批量处理(并行请求,性能更高)
所有请求同时发起,等待全部请求完成后再统一处理结果,适合请求量不大、不需要控制并发的场景,运行速度更快:
const myFunction = async (j) => { async function fetchFromApi(i) { const ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i const httpRequest = { method: "GET" } try { const response = await fetch(ApiEndpoint, httpRequest); if (!response.ok) { // 失败直接返回请求参数作为标识 return { type: 'fail', data: i } } else { const symbolData = await response.json(); console.log(JSON.stringify(symbolData)) return { type: 'success', data: JSON.stringify(symbolData) } } } catch (e) { // 额外捕获网络异常等报错 return { type: 'fail', data: i } } }; // 并行启动所有请求,等待全部执行完成 const results = await Promise.all(j.map(item => fetchFromApi(item))) // 过滤出所有失败的项得到failed数组 const failed = results.filter(item => item.type === 'fail').map(item => item.data) return failed } myFunction(["aaa", "abc"]).then(data=>console.log(data))
内容的提问来源于stack exchange,提问作者Sun Tianyi
相关产品推荐
相关产品推荐

