为什么 setTimeout 代码会被阻塞?

7
function test(){
  setTimeout(function(){
    var now=new Date();
    while((new Date()).getTime() < now.getTime()+5000){ }
    console.log('p')
  }, 0);
}

test();
test(); //it takes 10 seconds,the second test function runs after the first finished.

有人能解释一下这个是如何工作的吗?

JavaScript 不是“多线程”的;函数是串行执行的,而不是并行执行的。 - Salman A
2个回答

5
这是因为,当你将一个 function 传递给 setTimeout 并调用它时,该函数将根据提供的延迟时间(以毫秒为单位)被推入到 callBack 队列中。回调队列中的函数将按照它们被推入的顺序依次执行。所以在这种情况下,你通过运行一个 while 循环来阻塞了 callBack 队列中存在的 function 的代码流程。因此,第二次调用 test 需要10秒才能执行。
test(); //call 1
callBack queue ---->  [function(){ while(){} }]

test(); //call 2
callBack queue ---->  [function(){ while(){} }, function(){ while(){} }]

注意:只有在调用堆栈中没有要执行的内容时,回调队列才会开始执行。
更好的阅读材料,请参考 事件循环

那么,在 while(){} 中的代码不会同时执行吗? - lx1412
@lx1412 是的,回调队列中的函数将像普通数组中的函数一样被依次执行。 - Rajaprabhu Aravindasamy

2

如果您想要非阻塞实现,您需要用异步递归替换同步的while循环:

function test(x){
  setTimeout(function loop(now) {
    (new Date()).getTime() < now.getTime()+2000
     ? setTimeout(loop, 0, now)
     : console.log('p', x);
  },0, new Date())
}

test(1);
test(2);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接