Skip to main content

异步单线程

进程和线程

基础概念:

同步确保任务顺序执行,异步支持非阻塞操作,进程是系统中程序运行的基本单元,线程是进程中独立的执行路径,单线程按序处理任务,多线程则能并发执行多个任务。

浏览器是多进程的,核心包含:

  • 浏览器进程(Browser Process):负责管理用户界面、标签页和其他进程,相当于整个浏览器的大脑。
  • 渲染器进程(Renderer Process):每个标签页都有一个渲染器进程,负责页面的布局、渲染以及 JavaScript 执行等。

渲染进程 (浏览器内核)

浏览器的渲染进程是多线程的,页面的渲染,JavaScript 的执行,事件的循环,都在这个进程内进行,核心包括:

  • GUI 渲染线程:负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时,该线程就会执行。
  • JavaScript 引擎线程:也称为 JavaScript 内核,负责处理 Javascript 脚本程序、解析 Javascript 脚本、运行代码等。(例如 V8 引擎)

GUI 渲染线程与 JavaScript 引擎线程是互斥的,当 JavaScript 引擎执行时 GUI 线程会被挂起(相当于被冻结了),GUI 更新会被保存在一个队列中等到 JavaScript 引擎空闲时立即被执行。所以如果 JavaScript 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。

单线程的 JavaScript

产生原因:单线程与之用途有关,单线程能够保证一致性,保证 JavaScript 操作 DOM,不会出现 DOM 冲突。

  • 优点:实现比较简单,执行环境相对单纯
  • 缺点:只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段 Javascript 代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。

同步和异步

同步:在函数返回的时候,调用者就能够得到预期结果 异步:在函数返回的时候,调用者还不能够得到预期结果,而是需要在将来通过一定的手段得到

采用异步编程的原因:

  1. JavaScript 是单线程;
  2. 为了提高 CPU 的利用率。

消息队列与事件循环

  • 消息队列:消息队列是一个先进先出的队列,它里面存放着各种消息。
  • 事件循环:事件循环是指主线程重复从消息队列中取消息、执行的过程。

事件循环(eventloop)

主线程不断的从消息队列中取消息,执行消息,这个过程称为事件循环,这种机制叫事件循环机制,取一次消息并执行的过程叫一次循环。

事件循环是 JavaScript 实现异步的具体解决方案,其中同步代码,直接执行;异步函数先放在异步队列中,待同步函数执行完毕后,轮询执行 异步队列 的回调函数。

event-loop 过程:

执行同步代码(这属于宏任务) 同步执行完毕后,检查是否有异步要执行 执行所有的微任务 微任务执行完毕后,如果有需要就会渲染页面 执行异步宏任务,也是开启下一次事件循环

宏任务和微任务

微任务设计用于即时响应的轻量级操作,确保关键路径的高效执行。

宏任务则更适合处理耗时或定时触发的任务,维持程序的整体节奏。

微任务:promise.then(), process.nextTick(), MutationObserver()(监视器,监测 DOM 结构变化) 宏任务:script 脚本执行, setTimeout(), setInterval(), setImmediate(), I/O(输入输出), UI-rendering(页面渲染)