JS中return await调用getSpecificMonitorNews时结果被覆盖问题
问题原因
出现结果覆盖的核心原因是所有异步任务共用了同一个全局声明的newsContents对象引用:
- 单独调用
getSpecificMonitorNews(url)时,只有一个执行流修改这个对象,执行完打印就能拿到正确结果 - 用
Promise.all并发执行多个请求时,多个异步任务会先后修改同一个newsContents的属性,由于对象是引用类型,所有return出去的结果本质上都指向同一个内存地址,最后一次修改完成后,所有返回项都会变成最后一次请求拿到的内容。
修复方案
把newsContents的声明移到getSpecificMonitorNews函数内部,每次调用函数时都创建一个全新的独立对象,避免多个异步任务共享同一份数据:
async function getSpecificMonitorNews(url) { // 每次调用时新建独立的内容对象,不共享全局状态 let newsContents = { title: "", imageSrc: "", }; let monitorBaseUrl = "https://www.monitor.co.ug"; url = monitorBaseUrl + url; console.log(url) const data = await fetchPage(url); let $ = cheerio.load(data); newsContents.title = $(".title-medium").text(); newsContents.imageSrc = monitorBaseUrl + $(".lazy-img-container img").attr("src"); return newsContents; } async function getMonitorNews(urlNews) { // 简化冗余的async/await嵌套,直接返回Promise.all结果即可 return Promise.all( urlNews.map(url => getSpecificMonitorNews(url)) ); }
额外说明
- 异步并发场景下禁止使用跨调用共享的可变对象存储单次请求结果,否则必然出现竞态覆盖问题
async函数中如果只是等待一个Promise后直接返回结果,不需要额外写return await xxx,直接返回Promise本身即可,外层Promise.all会自动处理等待逻辑。
内容的提问来源于stack exchange,提问作者isaac
相关产品推荐
相关产品推荐

