我期望打印“asd”并承诺解决,但现实是不同的。代码卡在 while 循环中,并且“getI”始终返回 1,尽管它通过不同的方式进一步更改了几次。
let i = 1;
function getI() {
return i;
}
new Promise( resolve => {
while(getI() === 1) {
}
console.log('asd');
resolve();
})
i = 2;
setTimeout(() => i = 3, 1500);
new Promise(resolve => {
i = 4;
resolve();
})
这一切背后的机制是什么?
在浏览器或 Nodejs 环境中运行 Javascript 的一些相关事实:
setTimeout()
这样的函数只会通过事件循环触发回调函数while
循环(不包含await
)是Javascript中的阻塞结构,在while
循环完成并将控制权返回到事件循环之前,其他任何操作都不能运行。所以,考虑到所有这些,你的
while
循环就会永远运行。它占用了解释器,并且因为它占用了解释器并且没有其他东西可以运行,所以 i
的值永远不会改变,因此你的 while
循环永远无法完成并将控制权返回给事件循环。 setTimeout()
回调坐在那里等待在事件循环中运行,但永远不会运行,因为 while
循环永远不会将控制权返回给事件循环。 while
循环只是坐在那里并永远旋转,因为while
循环内的代码不会导致i
的值发生变化。
单线程、事件驱动代码的基本概念是解释器运行一段 Javascript 代码直到它返回。当它返回时,解释器返回到事件循环以查看还有什么正在等待运行,获取下一个事件,调用其回调,并类似地等待它返回,然后才能运行下一个事件。
像计时器这样的事件会排队,并且无法执行它们的回调,直到控制返回到事件循环并且直到它们在事件循环中轮到(因为其他事情可能会在它们之前运行)。