设计机制
浏览器为多进程应用,包含浏览器进程、网络进程、渲染进程等多个进程,各进程相互独立,互不影响。
渲染进程
渲染进程是浏览器进程中最为重要的进程,也是最为繁忙的进程,因为html页面解析、样式的计算、布局、js的运行均在渲染进程的主线程中运行,这也是为什么说js是一门单线程语言的原因,因为它只能在渲染主线程中运行。由于渲染主线程要处理的任务非常多,因此要提高渲染效率,在单线程的背景下,使用异步编程是解决线程阻塞提高渲染效率的最佳实现。
线程阻塞
当js执行以下内容时会造成线程阻塞
- 使用计时器
- 读取文件
- 网络请求
- 触发事件
想象一下,如果使用同步的形式变成,在执行以上内容时,主线程需要等待计时完成、读取完成、请求完成、等待事件触发等,在等待的时间内,主线程处于空闲状态,导致要执行的内容得不到执行,页面必然会卡顿甚至崩溃。
任务队列
因此,渲染主线程采取了一个绝妙的做法,当遇到线程阻塞时,将其交给其他线程去处理,当其处理完毕后,处理线程会将回调函数封装为任务并推送到任务队列中,渲染主线程再从任务队列中逐个提取执行,这样就可以保证渲染主线程永不堵塞。
如上图所示,所有待处理的任务均存放在任务队列中等待渲染主线程执行。而任务队列又有区分,在目前chrome的实现中至少包含了以下任务队列
- 微队列,存放需要最快执行的任务,具有最高优先级
添加微任务队列的主要方式是使用Promise、MutationObserver
例如:
//立即把一个函数添加到微任务队列
Promise.resolve().then(函数)
- 交互队列,存放用户操作后产生的事件处理任务,具有高优先级
- 延时队列,存放计时器到达后的回调任务,具有中优先级