返回

从浏览器进程到JavaScript单线程:最全面的JavaScript运行机制解析

前端

春天已至,三月的脚步声渐进,迎来早读文章分享。由@撒网要见鱼授权分享,一起开启今天的阅读之旅。

最近发现不少介绍JavaScript单线程运行的文章,很多只关注某个方面,说法也不统一,容易混淆。

为了理清这一知识点,我们将结合已有的认知和网上的参考资料,全面地解析JavaScript的运行机制。

浏览器多进程

浏览器的工作原理基于多进程架构,每个进程独立于其他进程运行,拥有自己的内存空间和资源,这样可以提高浏览器稳定性。

一个浏览器可能有多个进程:

  • 主进程:负责管理浏览器窗口、选项卡和插件。
  • 渲染进程:负责将HTML、CSS和JavaScript代码渲染为页面,每个选项卡对应一个渲染进程。
  • GPU进程:负责处理图形和视频的渲染,在涉及视频或3D效果的页面中更为重要。
  • 插件进程:负责处理浏览器插件,如Adobe Flash Player或Java插件。

JavaScript单线程

JavaScript在浏览器中是单线程运行的,也就是说,同一时间只有一个线程在执行代码。这种单线程模式有以下几个原因:

  • 为了保证JavaScript执行的一致性,避免多线程并发执行造成的数据竞争和不确定性。
  • JavaScript通常用于处理用户交互、动画和网络请求,这些任务往往是顺序执行的,不需要多线程。
  • 为了降低浏览器资源消耗和复杂性。

EventLoop

JavaScript单线程由EventLoop驱动,EventLoop是一个事件循环机制,不断轮询检查是否有事件发生,并执行对应的回调函数。

EventLoop由以下步骤组成:

  1. 检查任务队列,如果有任务,则执行。
  2. 检查微任务队列,如果有微任务,则执行。
  3. 如果没有任务或微任务,则阻塞等待,直到有事件发生。

EventLoop不断重复这三个步骤,直到所有任务和微任务都执行完毕。

任务队列

任务队列是存放宏任务的队列,宏任务是常规的JavaScript函数,当函数被调用时,它会被放入任务队列中。

EventLoop不断从任务队列中取出任务并执行,直到队列为空。

微任务队列

微任务队列是存放微任务的队列,微任务是Promise的回调函数、MutationObserver的回调函数和某些浏览器的requestAnimationFrame回调函数。

微任务队列的优先级高于任务队列,当微任务队列中有微任务时,EventLoop会先执行微任务,然后再去执行任务队列中的任务。

宏任务与微任务

宏任务与微任务的主要区别在于执行时机。

宏任务在任务队列中执行,通常在EventLoop的下一次循环中执行。而微任务在微任务队列中执行,通常在当前EventLoop循环中执行,在所有宏任务之前执行。

总结

JavaScript在浏览器中是单线程运行的,由EventLoop驱动,EventLoop不断轮询检查是否有事件发生,并执行对应的回调函数。

EventLoop由任务队列和微任务队列组成,任务队列存放宏任务,微任务队列存放微任务。

微任务队列的优先级高于任务队列,当微任务队列中有微任务时,EventLoop会先执行微任务,然后再去执行任务队列中的任务。

通过对JavaScript运行机制的深入理解,我们可以更好地编写出高效、可靠的JavaScript代码。