圈圈圆圆圈圈——js中的事件循环机制

106 阅读3分钟

今天,我们来聊聊JavaScript中的事件循环机制。

为什么需要事件循环机制

JavaScript是一门单线程的编程语言,它一次只能执行一个任务,这也意味着代码的执行是按照顺序进行的,一行接一行地执行。我们都知道的是,在JavaScript中的任务可以分为同步任务和异步任务,同步任务是按照顺序执行的任务,而异步任务则是在将来的某个时间点执行的任务。

事件循环机制就是一种用于管理和调度异步任务的执行顺序的机制。它确保了代码的顺序执行,并能够处理异步操作和事件的响应。

调用栈

  • 调用栈是一个存储函数调用的数据结构,它用于跟踪程序的执行位置。
  • JavaScript 引擎执行函数时,会将函数调用信息添加到调用栈的顶部,形成一个调用帧。
  • 当函数执行完成后,对应的调用帧会被从调用栈中移除。
  • 调用栈遵循"后进先出"(LIFO)原则,即最后一个进入调用栈的函数会首先执行和退出。

如果想对调用栈整个的执行过程有个更深入的了解,可以看看下面这篇文章,我这里就不再赘述。blog.csdn.net/qq_53225741…

任务队列

  • 任务队列是用于存储异步任务的队列,它包含待执行的回调函数。
  • 当异步任务完成时,回调函数会被添加到任务队列中。
  • 任务队列又分为微任务队列和宏任务队列。
  • 任务队列采用"先进先出"(FIFO)的顺序,即最早进入队列的任务会首先执行。

事件循环流程

  1. 首先整个script标签可以当作为一个宏任务来执行,
  2. JavaScript执行时,优先执行同步代码,此时同步代码会被添加到调用栈中,按顺序执行。
  3. 如果遇到异步任务(如定时器、网络请求等),会根据异步任务的不同(微任务和宏任务),它们会被添加到不同的任务队列中挂起,同时 JavaScript引擎会继续执行后续的代码。
  4. 当调用栈为空时,事件循环会从微任务队列中不断取出一个任务,并将其添加到调用栈中执行,直到微任务队列为空。
  5. 当微任务队列为空时,事件循环又会从宏任务队列中不断取出任务,并将其添加到调用栈中执行。需要注意的是,script标签是作为一个宏任务,那么我们就可以理解为一个宏任务中的代码又是一个script标签(这样说可能不太准确,但我觉得可以更好的理解循环的概念),那么其中的代码又是以上面的顺序来执行。
  6. 循环上述步骤,保持调用栈和任务队列的协同工作,直到所有任务都被执行完毕。

这种机制使得 JavaScript能够处理异步任务,并且在执行过程中保持响应性,避免阻塞主线程。通过合理地利用异步编程和事件循环机制,可以优化代码的性能和用户体验。

在执行宏任务或微任务的过程中,可能会产生新的任务,这些任务会被添加到相应的任务队列中,形成嵌套的事件循环。嵌套的事件循环会一直执行,直到所有任务队列为空。