异步行为疑问:递归setTimeout未执行完毕就执行后续代码的原因
为什么递归setTimeout完成前后续代码就执行了?
我来帮你拆解这个问题的核心——这其实是JavaScript**事件循环(Event Loop)**在搞事情!先看你的代码:
console.clear(); var a = 1; function logA() { if (a<11) { console.log(a); a++; setTimeout(logA, 100); } else { return; } } logA(); console.log("after set timeout");
调用栈和事件循环的完整流程
我一步步给你捋清楚调用栈里发生的每一件事:
- 首先,所有同步代码按顺序执行:
- 执行
console.clear(),完成后从调用栈弹出。 - 声明并赋值
a=1,完成后弹出。 - 声明
logA函数,只是定义不执行,跳过。 - 调用
logA(),把logA压入调用栈:- 此时
a=1<11,执行console.log(1),然后a变成2。 - 调用
setTimeout(logA, 100):这里注意!setTimeout不会立刻执行回调函数,它会把logA这个回调放到宏任务队列里排队,然后setTimeout本身执行完毕,从调用栈弹出。 - 第一次
logA函数执行完毕,从调用栈弹出。
- 此时
- 执行
- 现在调用栈空了吗?不,还有最后一行同步代码
console.log("after set timeout")!这行是同步任务,直接压入调用栈执行,所以你会先看到控制台打印出这句话。 - 等100毫秒后,浏览器会检查宏任务队列,发现里面有
logA回调,就把它压入调用栈执行:- 重复之前的逻辑:打印当前
a的值,a自增,再把下一个logA回调放进宏任务队列,直到a>=11时,logA执行return,不再添加新的宏任务,整个循环结束。
- 重复之前的逻辑:打印当前
简单来说:setTimeout是异步任务,它的回调不会阻塞同步代码的执行,同步代码会优先全部跑完,异步任务才会在调用栈空闲时依次执行。
内容的提问来源于stack exchange,提问作者sashaikevich
相关产品推荐
相关产品推荐

