为何while死循环中的setTimeout无法正常工作?
问题:为何log无法被重新设为true?
我想编写一个每秒递增1的简易计时器(当时不知道setInterval的存在),于是写下了如下代码:
let log : boolean = true; const setLogTrue = () => { log = true; }; let timer : number = 0 while (true){ if (log == true){ timer ++; console.log(timer); log = false; setTimeout(setLogTrue, 1000); } }
但这段代码仅输出1后就停滞,始终无法将log重新设为true。我无法找出问题所在,也无法通过调试终端追踪setTimeout的计时过程。
注:我并非询问实现方法,已知可通过setInterval或递归调用setTimeout实现:
使用setInterval的实现:
let timer : number = 0 const printTimer = () =>{ timer ++; console.log(timer); } setInterval(printTimer, 1000);
或另一种setTimeout写法:
let timer = 0; const printTimer = () => { console.log(timer++); setTimeout(printTimer, 1000); } printTimer();
我曾阅读过相关问题,但该问题解答的是“setTimeout不会暂停后续代码”,与我的问题不符。请问我错在哪里?
解答
核心问题出在JavaScript的事件循环机制上:
- JavaScript是单线程语言,所有同步任务都会在主线程的执行栈里依次执行,而异步任务(比如
setTimeout的回调函数)会被放到任务队列中,只有当主线程的执行栈完全清空时,才会从任务队列里取出任务执行。 - 你的代码里
while(true)是一个无限同步循环,它会一直霸占主线程,永远不会让执行栈为空。虽然你调用了setTimeout(setLogTrue, 1000),这个回调会在1秒后被加入任务队列,但主线程被while循环死死堵住,根本没机会处理任务队列里的回调,所以setLogTrue永远不会被执行,log也就永远无法被重新设为true。
简单来说,你的无限循环把主线程彻底堵死了,异步回调连运行的机会都没有。
内容的提问来源于stack exchange,提问作者Pintjens
相关产品推荐
相关产品推荐

