设计机制

浏览器为多进程应用,包含浏览器进程、网络进程、渲染进程等多个进程,各进程相互独立,互不影响。

image-20230313152306122

渲染进程

渲染进程是浏览器进程中最为重要的进程,也是最为繁忙的进程,因为html页面解析、样式的计算、布局、js的运行均在渲染进程的主线程中运行,这也是为什么说js是一门单线程语言的原因,因为它只能在渲染主线程中运行。由于渲染主线程要处理的任务非常多,因此要提高渲染效率,在单线程的背景下,使用异步编程是解决线程阻塞提高渲染效率的最佳实现。

线程阻塞

当js执行以下内容时会造成线程阻塞

  • 使用计时器
  • 读取文件
  • 网络请求
  • 触发事件

想象一下,如果使用同步的形式变成,在执行以上内容时,主线程需要等待计时完成、读取完成、请求完成、等待事件触发等,在等待的时间内,主线程处于空闲状态,导致要执行的内容得不到执行,页面必然会卡顿甚至崩溃。

任务队列

因此,渲染主线程采取了一个绝妙的做法,当遇到线程阻塞时,将其交给其他线程去处理,当其处理完毕后,处理线程会将回调函数封装为任务并推送到任务队列中,渲染主线程再从任务队列中逐个提取执行,这样就可以保证渲染主线程永不堵塞。

new

如上图所示,所有待处理的任务均存放在任务队列中等待渲染主线程执行。而任务队列又有区分,在目前chrome的实现中至少包含了以下任务队列

  • 微队列,存放需要最快执行的任务,具有最高优先级

添加微任务队列的主要方式是使用Promise、MutationObserver

例如:

//立即把一个函数添加到微任务队列
Promise.resolve().then(函数)
  • 交互队列,存放用户操作后产生的事件处理任务,具有高优先级
  • 延时队列,存放计时器到达后的回调任务,具有中优先级