js微任务输出
js微任务输出
for(var i= 0;i< 3; i++){setTimeout(function(){console.log('timeout' + i);})}new Promise(function(resolve){console.log('promise' +i);for(var i= 0;i< 1000;i++){i== 99 &&resolve();}console.log('promise'+ i);}).then(function() {console.log('then' + i);})console.log('global'+ i);
要理解这段代码的执行结果,需要结合变量作用域(var的特性)、同步/异步执行机制(同步代码→微任务→宏任务)来分析,具体步骤如下:
1. 变量作用域分析(核心)
代码中所有i均用var声明,var是函数作用域(非块级作用域),会发生变量提升,具体表现为:
- 第一个
for(var i=0; i<3; i++)中的i是全局变量(因在最外层)。 - Promise回调中
for(var i=0; i<1000; i++)中的i是局部变量(仅在Promise回调函数内有效,覆盖全局i)。
2. 代码执行顺序(同步→微任务→宏任务)
JavaScript执行优先级:同步代码先执行 → 同步执行完后执行微任务(如Promise.then) → 最后执行宏任务(如setTimeout)。
步骤1:执行第一个for循环(同步)
for(var i=0; i<3; i++){setTimeout(function(){ console.log('timeout' + i); })
}
var i声明提升到全局,循环过程:i从0→1→2→3(循环结束时i=3,因i=3不满足i<3)。- 每次循环的
setTimeout是宏任务,其回调会被放入宏任务队列(暂不执行),回调中引用的i是全局变量(最终为3)。
步骤2:执行new Promise(同步,Promise构造函数回调立即执行)
new Promise(function(resolve){console.log('promise' + i); // ①for(var i=0; i<1000; i++){ i==99 && resolve(); } // ②console.log('promise' + i); // ③
})
- 回调内的
var i是局部变量(变量提升到回调函数内,覆盖全局i)。- ①处:局部
i已声明但未赋值(仅提升),值为undefined,输出promiseundefined。 - ②处:循环执行,
i从0增至999时,i++变为1000(不满足i<1000,循环结束),此时局部i=1000;且i=99时触发resolve()(标记Promise为成功状态)。 - ③处:局部
i=1000,输出promise1000。
- ①处:局部
步骤3:执行全局同步代码
console.log('global' + i);
- 此处
i是全局变量(第一个for循环结束后i=3),输出global3。
步骤4:执行微任务(Promise.then)
.then(function() { console.log('then' + i); })
- Promise状态已成功,
then回调是微任务,同步代码执行完后立即执行。 - 回调中
i是全局变量(值为3),输出then3。
步骤5:执行宏任务(setTimeout回调)
- 第一个for循环中3个
setTimeout回调进入宏任务队列,此时全局i=3,每个回调均输出timeout3。 - 最终输出3次
timeout3。
最终执行结果(整理后)
promiseundefined
promise1000
global3
then3
timeout3
timeout3
timeout3
关键结论:var的函数作用域导致变量共享,同步→微任务→宏任务的执行顺序决定了输出时机,全局i最终为3,因此异步回调均输出3。
