事件循环
浏览器进程模型
一个进程有很多线程,线程是干活的人,所以一个进程至少一个线程
浏览器极其复杂,拥有多个进程
浏览器进程
负责:界面显示、交互、子进程管理
网络进程
渲染进程
会开启一个渲染主线程,负责执行
html\css\js
代码默认每个标签开启一个新渲染进程
渲染主线程
事件循环就发生在其中
- 解析html
- 解析css
- 计算样式
- 布局
- 图层处理
- 60帧
- 执行全局js代码
- 执行事件处理函数
- 执行计时器回调
渲染主线程任务如此繁重,要怎么调度任务呢?
事件循环
单线程是异步产生的原因,事件循环是异步的实现方式
- 一开始,渲染主线程进入一个死循环
- 每次循环检查消息队列中有没有任务,有任务渲染主线程就取走执行
- 其他所有线程可以随时向消息队列添加任务在末尾
但是遇到异步任务怎么办?
如何理解js异步?
答: js是单线程语言,因为他运行在渲染主线程中,而渲染主线程只有一个,且承载着诸多任务,如果采用同步,则其他任务被阻塞。
所以js采用异步来避免这种问题。遇到异步任务时,自己结束任务转而执行后续任务,交给其他线程去处理。其他线程完成异步任务时,把回调函数包装成任务加入到消息队列末尾。
优先级
任务没有优先级,但是消息队列有优先级
任务有类型之分,同种一任务必须在同一消息队列
浏览器必须准备一个微队列,微队列优先级最高
交互队列, 优先级高 ——(事件处理)
延时队列, 优先级中 —— (计时器)
##js计时器精准吗?
不精准,因为:1. js实际调用操作系统的时间。 2. 受到事件循环影响,计时器只能在渲染主线程空闲时运行
在浏览器上的事件循环
微任务一般比宏任务先执行,并且微任务队列只有一个,宏任务队列可能有多个。另外我们常见的点击和键盘等事件也属于宏任务
常见宏任务
- js主进程
- setTimeout()
- setInterval()
- setImmediate()
- requestAnimationFrame()
- postMessage()
常见微任务
- promise.then .catch .finally
- async/await
- Generator函数
- new MutationObserver()
- process.nextTick()
案例
1. await
await 123
: 转化为await Promise.resolve(123)
- await express : express一旦状态转为fulfilled,然后执行完当前代码,再把等待的代码代码推到微队列
- await syncExpress: === 没有await的情况
1 | async function asy1() { |
1 | output: 1,6, |
2. return Promise.resolve()
1 | Promise.resolve().then(()=> { |
1 | // 开始 |
总结
1 | ()=>{ |
另外:
1 | 如果 |