JavaScript实现Promise.all时let results = [], i;语法的运行逻辑疑问
问题解答
1. let results = [], i;的语法作用
这是JavaScript支持的同作用域多变量合并声明语法,等价于分开写的两行声明:
let results = []; let i;
这段声明的本意是初始化两个变量:
results:空数组,用来按输入顺序存储所有Promise的成功返回结果i:循环下标计数器,用来标记当前遍历到可迭代对象的第几个元素
你单独运行这行代码得到i为undefined是正常的,因为这行没有给i赋初始值。
2. 这段代码本身存在多处错误,无法正常运行
你疑惑的逻辑问题确实存在,这段手写的Promise.all实现是有bug的:
- 第一个问题就是
i没有赋初始值0,第一次执行i++时会把undefined转成数字NaN,后续用NaN作为数组下标赋值完全不符合预期。 - 第二个问题是异步回调的闭包引用错误:
then回调是异步执行的,等回调触发时外层的for循环已经执行完毕,此时i已经等于可迭代对象的总长度,所有回调都会把结果存到同一个下标位置,没法保证结果顺序和输入顺序一致。作者本来写了let current = i;想通过块级作用域存储当前下标,但是回调里根本没有用到这个变量,属于代码疏漏。 - 第三个问题是计数逻辑错误:代码里只在循环时给
counter做递增,成功回调里没有做递减操作,counter === 0的判断永远不会成立,就算所有Promise都成功也不会触发resolve。
3. 修正后的可运行实现如下
function all(iterable){ return new Promise(function(resolve, reject){ let counter = 0; let results = [], i = 0; // 给下标计数器赋初始值0 for(let p of iterable){ const currentIndex = i; // 存储当前循环的下标,供异步回调使用 counter++; Promise.resolve(p).then(function(res){ results[currentIndex] = res; // 用当前循环的下标赋值,保证顺序 counter--; // 每完成一个Promise就减1 if(counter === 0) resolve(results) // 所有Promise都完成时返回结果 }, reject); i++; } // 额外处理空输入的边界情况 if(counter === 0) resolve(results); }); }
内容的提问来源于stack exchange,提问作者vaultsort.com
相关产品推荐
相关产品推荐

