js之事件循环

JavaScript的事件循环是它的并发模型的核心部分,使得JavaScript能够在单线程中处理异步操作。事件循环允许JavaScript在执行代码时,同时进行非阻塞的I/O操作(如网络请求、文件操作等)。这个概念对于理解如何高效地构建交互式Web应用程序是至关重要的。

事件循环的工作流程

JavaScript运行时环境包含一个待处理消息的队列。每个消息都关联着一个用以处理这个消息的函数。当堆栈(包含当前执行的所有代码)为空时,事件循环会从队列中取出一个消息,然后处理它。这个处理包括调用与消息关联的函数(及其调用堆栈)。这个函数执行完毕后,堆栈空出,事件循环继续处理下一个消息,这个过程持续不断。

宏任务(Macrotask)与微任务(Microtask)

事件循环中的任务可以分成两种:宏任务(如setTimeout、setInterval、I/O操作)和微任务(如Promise.then、MutationObserver)。两者的主要区别在于它们被执行的时机。

宏任务(Macrotask): 每次执行完一个宏任务,都会检查微任务队列是否有任务,如果有,则会先执行微任务队列中的所有任务,然后才会执行下一个宏任务。

微任务(Microtask): 当前任务执行完毕后立即执行的任务。所有微任务执行完毕之后,若存在渲染操作,则会执行渲染操作,然后继续回到宏任务的执行。

事件循环的步骤

  1. 执行全局脚本:加载脚本后,全局脚本开始执行。
  2. 执行宏任务:一旦全局脚本执行完毕,事件循环会从宏任务队列中取出一个任务执行。
  3. 执行微任务:在当前宏任务执行完毕后,会检查微任务队列,如果队列不为空,则执行队列中的所有微任务。这些微任务可能会继续添加新的微任务到微任务队列中。事件循环会一直执行微任务队列中的任务,直到队列清空。
  4. 渲染:完成宏任务和微任务后,渲染界面(如果有必要的话)。
  5. 回到步骤2:继续从宏任务队列中取出下一个任务,重复这个过程。

例子

console.log('script start');

setTimeout(function() {
   
    console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
   
    console.log('promise1');
}).then(function() {
   
    console.log('promise2');
});

console.log('script end');

执行顺序:

console.log('script start');
  1. ‘script start’ 打印到控制台。这是同步代码的一部分,所以它首先执行。
setTimeout(function() {
   
    console.log('setTimeout');
}, 0);
  1. setTimeout是一个宏任务。尽管延迟是0,但这个setTimeout回调(任务)不会立即执行;它被加入到宏任务队列等待执行。在当前执行栈(包括紧接着执行的微任务)执行完之前,setTimeout的回调不会被执行。
Promise.resolve().then(function() {
   
    console.log('promise1');
}).then(function() {
   
    console.log('promise2');
});
  1. Promise.resolve()是立即解决的Promise,.then回调(设置的第一个promise1打印操作)被加入到微任务队列,将在当前宏任务的同步任务执行完毕后立即执行。

  2. 第二个.then(即promise2打印操作)也会成为一个微任务,它将在第一个.then执行后被加入到微任务队列。

console.log('script end');
  1. ‘script end’ 打印到控制台。这也是同步代码的一部分,紧随'script start'的打印之后执行。

至此,同步任务执行完毕。事件循环将会查看微任务队列,看是否有任务需要执行;在这种情况下,微任务队列中有两个由Promise产生的任务需要执行:

  1. ‘promise1’ 被打印到控制台。这是第一个微任务。

  2. 由于第一个.then的回调执行完毕,第二个.then的回调(作为微任务)现在执行,‘promise2’ 被打印到控制台作为第二个微任务。

至此,当前宏任务中的所有微任务都已经被执行。事件循环现在回转到宏任务队列,准备执行下一个宏任务:

  1. ‘setTimeout’ 的回调函数现在执行,因为它是在开始时通过setTimeout提交的宏任务。‘setTimeout’ 被打印到控制台。

最终的执行顺序是:

  1. ‘script start’
  2. ‘script end’
  3. ‘promise1’
  4. ‘promise2’
  5. ‘setTimeout’

相关推荐

  1. js事件循环

    2024-02-20 18:58:02       28 阅读
  2. js事件循环以及promise

    2024-02-20 18:58:02       30 阅读
  3. node.js事件循环相关步骤

    2024-02-20 18:58:02       33 阅读
  4. Node.js 中的事件循环(Event Loop)

    2024-02-20 18:58:02       18 阅读
  5. Vue.js事件循环(Event Loop)机制

    2024-02-20 18:58:02       13 阅读
  6. 简述浏览器和 Node.js 中的事件循环

    2024-02-20 18:58:02       11 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-20 18:58:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-20 18:58:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-20 18:58:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-20 18:58:02       20 阅读

热门阅读

  1. Qt之QChar类的字符判断

    2024-02-20 18:58:02       23 阅读
  2. Qt标准对话框设置

    2024-02-20 18:58:02       29 阅读
  3. 算法训练营day31,贪心算法5

    2024-02-20 18:58:02       30 阅读
  4. 阿里云上关于EDAS发布方式

    2024-02-20 18:58:02       19 阅读
  5. HTML单击图片独立放大

    2024-02-20 18:58:02       26 阅读
  6. 32RTC&BKP

    32RTC&BKP

    2024-02-20 18:58:02      30 阅读
  7. CSS进阶平面转换

    2024-02-20 18:58:02       25 阅读
  8. 算法-贪心算法

    2024-02-20 18:58:02       24 阅读
  9. Chapter 8 - 11. Congestion Management in TCP Storage Networks

    2024-02-20 18:58:02       32 阅读
  10. Windows如何安装ctcdecode

    2024-02-20 18:58:02       27 阅读
  11. big three(c++)

    2024-02-20 18:58:02       30 阅读
  12. Docker中部署flink集群的两种方式

    2024-02-20 18:58:02       30 阅读