并发调用含Promise.all()的函数时参数异常问题求助
问题诊断:对象引用而非闭包问题
嘿,我来帮你梳理下这个问题——其实这不是闭包的锅,核心是对象的引用赋值导致的,这是JavaScript里很容易踩的一个坑!
问题根源
当你写这段代码的时候:
let personParams = globalParams;
你并没有创建一个新的对象,只是把globalParams这个对象的引用赋值给了personParams。也就是说,所有循环迭代里的personParams其实都指向同一个内存地址里的对象——也就是最开始定义的globalParams。
所以每次循环中修改personParams.name和personParams.location,本质上都是在修改同一个globalParams对象。当Promise.all最终执行完成时,这个对象已经被最后一次迭代(John那一次)修改完毕了,自然所有结果里的参数集合都显示成最后一次的内容。
解决方案:每次迭代创建新对象
要解决这个问题,我们只需要在每次循环时创建一个新的对象,把globalParams的属性复制进去,再添加当前person的信息即可。有两种常用方式:
方式1:使用对象展开运算符(ES6+)
这是最简洁的写法:
let personParams = {...globalParams};
方式2:使用Object.assign
如果需要兼容更老的环境,可以用这个方法:
let personParams = Object.assign({}, globalParams);
修改后的完整代码
let promiseArray = []; // top level array of promises let globalParams = { date: "2018-05-20" }; let people = [ {name: "Tom", location: "Philadelphia"}, {name: "Bob", location: "Austin"}, {name: "John", location: "Philadelphia"} ]; people.forEach( person => { // 每次迭代创建新的参数对象,复制globalParams的属性 let personParams = {...globalParams}; personParams.name = person.name; personParams.location = person.location; // Push promise to array promiseArray.push(assembleResults(personParams)); }); Promise.all(promiseArray).then( results => { console.log("Final Output:", results); }) // individual data aggregation function function assembleResults(iterationParams) { let promise1 = Promise.resolve({data: "Type A data about " + iterationParams.name}); let promise2 = Promise.resolve({data: "Type B data about " + iterationParams.name}); let promise3 = Promise.resolve({data: "Type C data about " + iterationParams.name}); return Promise.all([promise1, promise2, promise3, iterationParams]) }
更紧凑的写法
你还可以一步到位合并所有属性,让代码更简洁:
let personParams = { ...globalParams, name: person.name, location: person.location };
这样修改后,每个结果里的参数集合都会对应各自的person信息,完全符合你的预期!
内容的提问来源于stack exchange,提问作者Shaun Hurley
相关产品推荐
相关产品推荐

