Skip to content
大纲

异步

css 的加载

  • CSS 文件是并行下载的
  • CSS 的下载不会阻塞后面 JS 的下载,CSS 加载解析完成之后,再执行下面的 JS。

JS 的加载

  • 并行加载 JS 文件
  • 加载或者执行 JS 时会阻塞构建 DOM 树,只有等到 js 执行完毕,浏览器才会继续解析 DOM。没有 DOM 树,浏览器就无法渲染。
  • 这是由于 JS 引擎线程 与 GUI 渲染线程 互斥。至于互斥的初衷,主要是因为加载的 JS 中可能会创建,删除节点等,这些操作会对 DOM 树 产生影响,如果不阻塞,等浏览器解析完标签生成 DOM 树后,JS 修改了某些节点,那么浏览器又得重新解析,然后重新生成 DOM 树

改变外链 JS 的加载时机、顺序

  • defer 和 async 都是异步的,主要的区别在于执行顺序以及执行的时间
  • async 标志的脚本文件一旦加载完成就会立即执行,并且不会按照书写顺序,谁下载好了就直接执行
  • defer 标志的脚本文件会严格按照书写顺序执行,并且,会在 DOMContentLoaded 事件之前执行

消息队列:是 V8 引擎 除了主线程任务外,额外维护的一个队列,主要存放要执行的任务(函数)

事件循环

  • 主线程运行产生了执行栈,在调用执行栈的过程中调用了一些异步函数。
  • 当满足异步函数的触发条件时,会将对应的回调函数推送到消息队列中。
  • 当主栈中的代码执行完毕时,会触发一次页面渲染,然后创建新的主栈。
  • 将消息队列中的回调函数推送到主栈。然后顺序执行主栈的任务。
  • 反复循环执行上述过程就是时间循环。

一开始整段脚本作为第一个宏任务执行 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列 当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空 执行浏览器 UI 线程的渲染工作 检查是否有 Web worker 任务,有则执行 执行队首新的宏任务,回到 2,依此循环,直到宏任务和微任务队列都为空

node 的 EventLoop

  • 执行 定时器回调 的阶段
  • 轮询 (英文叫 poll) 阶段
  • check 阶段

timer 阶段 I/O 异常回调阶段 空闲、预备状态 (第 2 阶段结束,poll 未触发之前) poll 阶段 check 阶段 关闭事件的回调阶段

浏览器中的微任务是在每个相应的宏任务中执行的,而 nodejs 中的微任务是在不同阶段之间执行的。

process.nextTick 是一个独立于 eventLoop 的任务队列。在每一个 eventLoop 阶段完成后会去检查这个队列,如果里面有任务,会让这部分任务优先于微任务执行