为何含Promise的for循环执行模式不同?then回调花括号的作用解析
为什么一对花括号会让Promise的执行顺序天差地别?
嘿,这个问题其实戳中了箭头函数一个超级容易踩坑的细节,我来给你把这个逻辑掰扯明白~
核心原因:箭头函数的两种写法带来的返回值差异
箭头函数有两种定义方式,这直接决定了它的返回值:
- 简洁体(不带花括号):
() => 表达式
这种写法会自动返回表达式的结果,不需要额外写return。 - 块体(带花括号):
() => { 代码语句 }
这种写法里,如果你不手动写return,函数就会默认返回undefined。
结合你的代码拆解差异
先把你的两种写法整理出来,方便对比:
写法1:不带花括号(异步串行执行)
function loadIngs() { let p = Promise.resolve(); for (let [k, v] of someArray) { // 箭头函数用简洁体,自动返回new Promise的结果 p = p.then(() => new Promise(resolve => { const delay = Math.random() * 2000; console.log(`${k}:${v} comes delayed for ${delay}`) setTimeout(() => { console.log("executes some function") resolve(); }, delay); })); } }
这里的then回调返回了一个新的Promise,then方法会**等待这个Promise完成(也就是resolve()被调用)**之后,才会执行下一个循环里的then回调。所以每个列表项的延迟操作是串行执行的,也就是你说的“异步执行”。
写法2:带花括号(同步触发所有延迟)
function loadIngs() { let p = Promise.resolve(); for (let [k, v] of someArray) { // 箭头函数用块体,没有return,默认返回undefined p = p.then(() => { new Promise(resolve => { const delay = Math.random() * 2000; console.log(`${k}:${v} comes delayed for ${delay}`) setTimeout(() => { console.log("executes some function") resolve(); }, delay); }) }); } }
这里的箭头函数是块体,没有写return,所以它的返回值是undefined。而then方法的规则是:如果回调返回的不是Promise,就会自动用Promise.resolve(undefined)把它包装成一个立即resolve的Promise。
这就意味着,循环里的每个then都会立即完成,不会等待内部的new Promise执行完毕。所有的setTimeout会几乎同时被触发,看起来就像是“同步执行”了。
补个小验证:加个return就一致了
如果在带花括号的写法里手动加上return,效果就和不带花括号的完全一样了:
p = p.then(() => { // 显式返回Promise,then会等待它完成 return new Promise(resolve => { // ... 原代码不变 }) });
总结一下:那对花括号改变了箭头函数的返回值,进而改变了then方法的等待逻辑——返回Promise就等,返回undefined就直接走下一步,这就是差异的根源~
内容的提问来源于stack exchange,提问作者Hugo Rodríguez
相关产品推荐
相关产品推荐

