JavaScript回调中的实际运行时是什么



我试图理解JS回调。在下面的例子中,A是在100毫秒后执行还是立即执行?

每个A,B,C执行的实际时间是多少?0女士:"A"(或100 ms ?)100 ms:"C"100女士:"B">

function wait(ms) {
let waitUntil = Date.now() + ms
while (Date.now() < waitUntil) { continue }
}
document.querySelector('#start-button').onclick = () => {
console.log('A')
setTimeout(() => {
console.log('B')
}, 50)
wait(100)
console.log('C')
}

如果修改为:

function wait(ms) {
let waitUntil = Date.now() + ms
while (Date.now() < waitUntil) { continue }
}
document.querySelector('#start-button').onclick = () => {
console.log('A')
setTimeout(() => {
console.log('B')
}, 150) // 150ms instead of 50ms
wait(100)
console.log('C')
}

实际运行时间是多少?它是0女士:100 ms: C150ms: B(或100ms+150ms=250ms)

我冒昧地让它为您运行。我还大幅增加了延迟,以便更清楚地说明这一点。您可以看到,在单击start按钮之后,在整个lambda onclick函数完成其执行之前,您实际上没有得到任何输出到控制台,直到阻塞线程的wait调用完成才可以得到输出。但是,A日志语句确实先执行,并且时间戳比C语句早了整整15秒。

有趣的是,B语句的setTimeout延迟实际上被忽略了,并被阻塞线程的wait语句所取代。在等待块完成后,在触发该函数时引入了10ms的小延迟。然而,如果你把等待延迟减少到小于setTimeout给定的延迟,它会在给定的时间延迟后执行。

所以时间是这样的:

A: 0, but it's printed after the wait delay
C: the wait delay
B: the wait delay + <10ms

同样值得注意的是,块的执行时间可以在这里或那里考虑到额外的毫秒,正如您可以通过运行块看到的那样。如果您的延迟是200ms,那么它很可能显示201ms的日志时间。如果块变得更复杂,需要更长的时间来执行,这种效果会更加明显。

function wait(ms) {
let waitUntil = Date.now() + ms
while (Date.now() < waitUntil) { continue }
}
document.querySelector('#start-button').onclick = () => {
console.log('A', Date.now())
setTimeout(() => {
console.log('B', Date.now())
}, 500)
wait(2000)
console.log('C', Date.now())
}
<button id="start-button">Start</button>

这里是更短的等待呼叫。

A: 0, but it's printed after the wait delay
C: the wait delay
B: 500ms

function wait(ms) {
let waitUntil = Date.now() + ms
while (Date.now() < waitUntil) { continue }
}
document.querySelector('#start-button').onclick = () => {
console.log('A', Date.now())
setTimeout(() => {
console.log('B', Date.now())
}, 500)
wait(200)
console.log('C', Date.now())
}
<button id="start-button">Start</button>

答案是:你无法确定。你可以"期待"什么?A将被立即打印出来,因为它没有等待时间。

Javascript引擎在单线程上运行。没有什么是"同时"发生的。而是"非常接近"。所以引擎可能会决定你的"繁忙循环"(wait()函数)将在运行timeout()时获得优先级,该timeout()在第一个示例中设置为50ms,因此您将看到C在b之前打印,这可能会发生,并且不同的浏览器可能会有不同的行为。

如果您在B和C上都使用了timeout(),您可能会看到更多的确定性行为,但由于您使用的是忙循环,因此所有的赌注都取消了。

在第二个示例中,B和C之间有50ms足够的时间,您可以期望它们以逻辑顺序出现。

最新更新