mortal-cultivation-biography / daydayup

A FE interview-questions collection repo.
8 stars 0 forks source link

为什么为任务队列清零才执行宏任务 #40

Open nmsn opened 1 year ago

nmsn commented 1 year ago
nmsn commented 1 year ago

EventLoop 事件循环机制

js 是单线程的

浏览器是多线程的

js 的代码只能在一个线程上运行,也就是说同时只能执行一个 js 任务,原因是设计之初是浏览器用来供用户交互和操作 dom 的,避免复杂性,设计成这样的

既然JS是单线程的,那么诸如onclick回调,setTimeout,Ajax这些异步都是怎么实现的呢?是因为浏览器或node(宿主环境)是多线程的,即浏览器搞了几个其他线程去辅助JS线程的运行

浏览器线程

GUI 渲染线程

负责渲染浏览器页面 html 元素,当界面需要重绘 repaint 或者某些操作引发回流 reflow 时,该线程就会执行

当 js 引擎运行脚本期间,gui 渲染线程都是处于挂起状态的

js 引擎线程

js 内核,负责处理 js 脚本主程序 一直等待 任务队列 中任务的到来,然后解析 js 脚本,运行代码 浏览器中的一个 tab (一个页面,也就是一个进程)中无论什么时候就只有一个 js 线程在运行 js 程序

gui 渲染线程和 js 引擎线程是互斥的,如果 js 执行的时间过长,就会造成页面的渲染不连贯,导致页面渲染加载阻塞

定时器触发线程

定时器 setInterval 与 setTimeout 所在的线程

浏览器定时器并不是 js 引擎技术的,因为 js 引擎单线程,如果处于阻塞线程状态就会影响计时的准确,因此通过单独线程来计时更为合理

定时器到时间后就会把回调函数放到任务队列中,等待 js 引擎处理

浏览器事件线程

用来控制事件

当 js 引擎执行代码如鼠标点击 click,onload 等事件,会将对应任务添加到事件触发线程中

由于 js 单线程,这个待处理的任务队列中的事件都得排队等待 js 引擎处理

http 请求线程

在 XMLHttpRequest 连接后是通过浏览器新开一个线程请求,将监测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件放到 js 引擎任务队列中等待处理

事件循环 EventLoop 机制

浏览器执行代码的过程中,js 引擎会讲代码进行分类,分别分到这两个队列中 宏任务 macrotask 和 微任务 microtask

常见宏任务

常见微任务

微任务是宏任务的组成部分,微任务与宏任务是包含关系,并非前后并列,宏任务包含微任务,如果要谈微任务,需要指出它属于哪个宏任务才有意义

image

requestAnimationFrame 它既不能算宏任务,也并非是微任务.它的执行时机是在当前宏任务范围内,执行完同步代码和微任务队列后再执行.它仍然属于宏任务范围内,但是是在微任务队列执行完毕后才执行