思考这段代码会打印什么?
let i = 0;
for(i = 0; i<6;i++){
setTimeout(()=>{
console.log(i);//打印6个6
},0)
}
我想着应该打印输出的应该是0,1,2,3,4,5啊!为什么会打印出6个6呢?
查了一下MDN文档发现下面这个例子。
MDN的栗子
// 超时延迟部分
function fn(){
console.log("我应该出现在第一行");
}
setTimeout(fn,0);
console.log('我应该出现在第二行');
//理想状态应该就是按照上面说的打印输出;
//可是控制台打印输出的是:
"我应该出现在第二行"
"我应该出现在第一行"
出现这个结果的原因是,尽管
setTimeout以0ms的延迟来调用函数,但这个任务已经被放入了队列中并且等待下一次执行;并不是立即执行;队列中的等待函数被调用之前,当前代码必须全部运行完毕,因此这里运行结果并非预想的那样。
遵循先来先出原则
用图可以看出setTimeout中fn会放在宏任务队列中,全部代码执行完后才会执行fn,主线程的for循环已经执行完了,此时i的值是6。fn在调用console.log(i)会打印出6个6了。
计时器由浏览器新开一个线程执行(区别于主线程),到点把回调放入宏任务队列;
主线程等待同步代码执行完毕 -> 清空当前循环微任务队列(这里微任务队列为空) -> 取出宏任务队列中下一个任务(即 setTimout 回调)执行,如此循环往复直至清空所有任务队列;
理想状态
for(let i = 0; i<6;i++){
setTimeout(()=>{
console.log(i);//打印0,1,2,3,4,5
},0)
}
let i 的作用域只在循环里面。
let i=0;
for(i=0;i<6;i++){
fn(i);
}
function fn(f){
setTimeout(()=>{
console.log(f)
},0)
}