如何在reduce()函数中等待异步函数执行?解决异步请求致结果为空问题
解决异步请求在reduce中导致结果为空的问题
这个问题我之前也碰到过!核心原因就是reduce是同步执行的,而你里面的request是异步回调——等reduce循环完返回初始空数组的时候,所有的请求还在后台跑呢,console.log自然拿不到结果。
要解决这个问题,我们需要把异步操作转换成Promise,然后用Promise.all或者异步版的reduce来处理,下面给你两种可行的方案:
方案一:用Promise.all并行处理(推荐,效率更高)
首先把request包装成返回Promise的函数,这样我们就能用async/await来等待异步操作完成:
// 把request包装成Promise function checkTodayThread(item) { return new Promise((resolve, reject) => { request(item.href, function(error, response, html) { if (error) { // 请求失败时,可以选择reject抛出错误,或者resolve(null)忽略错误 return reject(new Error(`请求${item.href}失败: ${error}`)); // 如果想忽略失败的请求,就用下面这行: // resolve(null); } const thread = cheerio.load(html); const hasTodayTag = thread('div#ignmsgbttns1').parent().parent().find("b:contains('Today')").text(); // 符合条件返回item,否则返回null resolve(hasTodayTag ? item : null); }); }); } // 批量处理所有item async function getValidThreads() { try { // 把每个item转换成Promise const threadPromises = newItems.map(item => checkTodayThread(item)); // 等待所有Promise完成,拿到所有结果 const allResults = await Promise.all(threadPromises); // 过滤掉不符合条件的(包括请求失败返回的null) const newThreads = allResults.filter(item => item !== null); console.log(newThreads); return newThreads; } catch (err) { console.error('处理请求时出错:', err); } } // 调用函数 getValidThreads();
这种方式是并行执行所有请求,效率比串行高很多,适合大部分场景。
方案二:用异步版reduce串行处理
如果你需要串行执行请求(比如怕请求太频繁被限制),可以用异步版的reduce,但要注意每次都要等待之前的累加结果:
async function getValidThreadsWithReduce() { try { const newThreads = await newItems.reduce(async (accPromise, item) => { // 先等待上一轮的累加Promise完成,拿到当前的数组 const acc = await accPromise; try { const thread = await checkTodayThread(item); if (thread) { acc.push(thread); } } catch (err) { console.error(`跳过失败的请求${item.href}:`, err); } return acc; }, Promise.resolve([])); // 初始值是一个已resolve的空数组Promise console.log(newThreads); return newThreads; } catch (err) { console.error('整体处理出错:', err); } } getValidThreadsWithReduce();
这个版本是串行执行请求,每处理完一个item再处理下一个,适合对请求频率有要求的场景。
关键要点总结
- 同步的
reduce无法直接处理异步回调,必须把异步操作转换成Promise - 优先用
map + Promise.all的并行方案,效率更高 - 记得处理请求失败的情况,避免整个流程因为单个请求失败而中断
内容的提问来源于stack exchange,提问作者Getter Jetter
相关产品推荐
相关产品推荐

