gpt4 book ai didi

javascript - 异步 JavaScript 程序中的函数调用到底是如何排序的?

转载 作者:行者123 更新时间:2023-12-03 08:32:21 25 4
gpt4 key购买 nike

我正在学习 JavaScript (JS) 中异步编程的概念。但是,我很难理解这一点。这几天我一直在网上阅读各种文章来理解它,但我无法理解其中的想法。

所以,这是我的疑问:

setTimeout(function(){ alert("Hello 1"); }, 3000); // .....(i)
console.log("Hi!"); // .....(ii)
setTimeout(function(){ alert("Hello 2"); }, 2000); // .....(iii)
  1. 考虑上面的代码。我了解到 JS 使用调用堆栈和事件队列来排序指令的执行。在上面的代码中,当 JS 解释器看到 (i) 行时,它会将 setTimeout 排入事件队列,然后移动到 (ii),将其放入调用堆栈中,执行然后转到 (iii),再次将 setTimeout 排入事件队列(并且该队列非空),对吗?

  2. 如果我在上述问题中所写的内容是正确的,那么一旦我们到达代码末尾,因为调用堆栈为空,setTimeout就会排队到事件中 -队列被一一执行,对吗? - 这意味着如果我们假设(例如)10ms 到达代码末尾,那么由于事件队列在前面有 setTimeout (i) ,它等待3秒,然后弹出警报:“Hello 1”,在时间= 3010ms时,将其出队,类似地setTimeout (iii) 再过 2 秒后执行,然后在 时间 = 5010ms 时弹出警报:“Hello 2”,对吗?

  3. 假设我们使用带有一些回调函数的 addEventListener(),而不是 (i) 和 (iii) 处的 setTimeout。即使在这种情况下,事件监听器的回调函数是否会排入事件队列?我觉得它们不会排队,因为我们可以在 (i) 的回调之前触发 (iii) 的回调。那么,在这种情况下到底发生了什么?除了调用堆栈和事件队列之外,还有其他东西可以以某种方式存储有关它们的信息并相应地触发它们的回调吗?

简而言之,这些说明是如何准确排序的?后台究竟发生了什么?

如果您能提供全面的答案,我将非常感激。如果您还可以提供有关此主题的一些综合 Material 的链接,那就太好了。

感谢您的帮助!

最佳答案

您可能已经知道,JavaScript 引擎现在在单线程上执行,那么异步操作是如何处理的呢?您在下面的陈述中部分正确,但还有更多内容:

Consider the above code. I learnt that JS uses a call-stack and anevent-queue to order the execution of instructions.

确实,我们确实有一个调用堆栈和一个事件循环。但我们还有WEB API 环境回调队列微任务队列

每当有任何异步任务时,它都会移动到 WEB API 环境,例如,当您在“src”属性中有一个带有非常大图像的标签时,该图像不会同步下载,因为这会阻塞线程,而是移至加载图像的 WEB API 环境中。

<img src="largeimg.jpg">

现在,如果您想在图像加载后执行某些操作,则需要监听图像的“load”事件。

document.querySelector('img').addEventListener('load', imgLoadCallback);

现在,一旦图像加载完毕,该回调函数仍然不会执行,而是被移入回调队列。回调函数在回调队列中等待,事件循环将检查同步代码,并等待直到调用堆栈为空。一旦调用堆栈为空,事件循环将在一次事件循环周期中将回调函数中的第一个插入调用堆栈。这就是回调函数被执行的时候。

但是,当存在诸如 Promise 之类的微任务时,情况就会发生变化。当有 Promise 时,它​​会被发送到微任务队列。微任务将始终优先于回调,并且它们可以并且将会停止回调直到它们被执行,事件循环将始终优先考虑微任务。

这就是 JavaScript 调用堆栈、事件循环、回调队列、微任务队列和 WEB API 环境的工作原理。

现在运行下面的代码,在运行之前尝试猜测结果。它将与我上面所写的完全一样:

//Synchronous Code - Always prioritized over async code
console.log('Asynchronous TEST start');

//It is a 0 Second Timer, But a timer is not a microtask
setTimeout(() => console.log('0 sec timer'), 0);

//Promise is a microtask
Promise.resolve('Resolved promise 1').then(res => console.log(res));

//2nd promise is a microtask too
Promise.resolve('Resolved promise 2').then(res => {
for (let i = 0; i < 1000000000; i++) {} //very large loop
console.log(res);
});

//Synchronous Code - Always prioritized over async code
console.log('Test end');

以上代码片段剧透警告:

可以看到,定时器虽然是0秒定时器,但最终运行到了最后,但实际上并没有在0秒处执行。这是为什么?因为 Settimeout 使用回调,而 Promise 是微任务,所以微任务优先级始终大于回调优先级

关于javascript - 异步 JavaScript 程序中的函数调用到底是如何排序的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64756522/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com