前端资源&前端学习资料

SetTimeout(fn,0)的问题

2017-02-23  本文已影响60人  神奇的少年

先来看看代码

console.log('a');
setTimeout(function(){
  console.log('b');
},0);
console.log('c');

你肯定知道这个结果是acb


为什么呢?其实这个问题在StackOverflow已经有人回答的很好了点击查看,如果还有不明白的话可以看Philip Roberts这个小伙子的视频点击查看,我是在这两个地方学习的,讲的很不错!

因为javascript是单线程语言,单线程运行同时,它有一个单一的调用堆栈,它可以做一件事的时间,这就是一个单独的线程装置

好吧,简单来说就是,javascript是一个单线程语言,它一次只能做一件事情,它不能一边做着setTimeout另一边执行你下面的代码,也就是说,它不能执行完console.log('a');之后就开始给你setTimeout(callback,0);还同时给你执行下面的console.log('c');吧,因此,浏览器会把延迟操作推到回调任务队列

这里要说一个事件循环,它只做一件很简单的事情,就是查看堆栈,并查看任务队列,如果堆栈是空的,它需要回调队列上的第一件事,将它推送到可以有效运行它的栈.所以我们看到,setTimeout被浏览器推到回调队列,然后继续执行堆栈上需要执行的代码,检索到堆栈是空的,去回调队列上拿任务回来执行.所以结果就为acb

我随便画了一下,我觉得应该差不多

1.先执行console.log('a');
2.看到有延迟操作or回调函数,推到回调队列
3.继续向下执行console.log('c');


4.执行完console.log('c');之后下面没有任务(代码)了,把回调队列上的任务拉过来

5.再执行setTimeout

记住,事件循环,它必须等到堆栈清除,才能将回调队列推送到堆栈上继续运行


那么现在看一个情况

function foo(){
  return foo();
}
foo();

这样做,你的堆栈会炸掉哈哈哈,浏览器会告诉你Maximum call stack size exceeded

就像它报错的形状一样,堆栈都放不下了,超过最大堆栈大小


那么再来看练习题中那个setTimeout的题目是不是就很好理解了?

for(var i=0;i<=3;i++){
  setTimeout(function(){
    console.log(i);
  },0):
}
//4444

如果你问为什么是4444,你是不是忘了for循环里的i++,这时候你再来访问i,人家早就+到4了


欢迎纠正错误!!请赐教

上一篇 下一篇

猜你喜欢

热点阅读