1-2-JS异步进阶(前端面试知识总结)

JS 异步进阶

event loop(事件循环/事件轮询)

首先需要知道的是

1. js是单线程运行的
2. 异步要基于回调来实现
3. event loop就是异步回调的实现原理

js 是如何执行的

1. 从前到后,一行一行执行
2. 如果某一行执行报错,则停止下面代码的执行
3. 先把同步代码执行完,再执行异步

Event Loop 的定义

event loop是js处理异步任务的核心机制,它决定了代码的执行顺序,确保单线程js也能高效处理异步任务,保证不会因为某个任务阻塞了整个页面

Event Loop 执行过程

1. 同步代码,一行一行放在call stack 执行
2. 遇到异步,会先“记录”下,等待时机(定时、网络请求)
3. 时机到了,就移动到callback queue中
4. 如果call stack为空(即同步代码执行完毕),Event Loop开始工作
5. 轮询查询callback queue, 如有则移动到call stack执行
6. 然后继续轮询查找(永动机一样)

每次时间循环(一次event loop)的执行顺序

  1. 执行同步代码
  2. 执行所有微任务
  3. dom渲染
  4. 执行一个宏任务
  5. 回到步骤2(执行所有微任务)
  6. 执行下一个宏任务
  7. 重复循环

DOM 事件和 event loop

1. js是单线程的
2. 异步(setTimeout, ajax, promise)使用回调,基于event loop
3. dom事件(click, keydown等)也使用回调,基于event loop

宏任务 macroTask 和微任务 microTask

宏任务

宏任务是主流程的任务单元,每次时间循环都会从任务队列取出一个宏任务执行,然后执行所有微任务

包含

API 环境 说明
setTimeout 浏览器&Node.js 设定定时器,到时间后执行
setInterval 浏览器&Node.js 每隔一定时间执行一次
setImmediate Node.js 当前时间循环结束后执行(类似于 setTimeout(0)),但更快
requestAnimationFrame 浏览器 下一帧前执行,大约 16ms 一次
requestIdleCallback 浏览器 浏览器由空闲时间时执行
DOM事件 浏览器 click、keydown等
I/0 任务 Node.js 文件读取,网络请求等
UI 渲染任务 浏览器 由浏览器决定合适执行页面重绘

微任务

微任务是更小粒度的任务单元,优先级更高,会在当前宏任务执行完后,紧接着执行,微任务优先级要高于宏任务

包含

API 环境 说明
Promise.then()/Promise.catch()/Promise.finally() 浏览器&Node.js Promise 解析后执行
async/await 浏览器&Node.js Promise 解析后执行
MutationObserver 浏览器 监听 DOM 变动,触发回调
queueMicrotask 浏览器&Node.js 手动创建微任务
process.nextTick() Node.js Node.js 特有,优先级比普通微任务更高,在当前阶段执行

浏览器的渲染时机

浏览器一般在每一帧进行一次页面渲染,默认目标是60fs,即16.67ms进行一次渲染,但event loop的任务调度可能会影响渲染时机

一次完整的浏览器帧

  1. 执行js(同步任务+微任务+谁宏任务)
  2. 计算样式
  3. 布局
  4. 绘制
  5. 合成
  6. 浏览器空闲时间,可能触发requestIdleCallback
  7. 下一帧的开始

总结:

  1. UI渲染通常发生在所有同步任务和微任务执行完毕后,而宏任务则在UI渲染发生之后才会触发
  2. requestAnimationFrame会在下一帧渲染前执行
  3. 微任务执行过多会可能会阻塞UI渲染(微任务无限递归)
  4. 过场的同步任务会阻塞渲染,导致页面卡顿
  5. 同步代码 -> 微任务代码 -> 页面渲染 -> 宏任务代码 -> 微任务代码(下一event loop) -> 页面渲染 -> ....
  6. 微任务是ES6语法规定的 ,宏任务是浏览器规定的

requestIdleCallback

执行时机:

  1. 浏览器一帧的主要任务完成后(同步代码、微任务、渲染等),如果还有时间,就执行
  2. 如果没有足够的空闲时间,可能会被延迟到下一帧或更晚执行
  3. 如果设置了超过时间,超过改时间后无论浏览器是否空闲,都会执行

Promise

三种状态:

pending、fulfilled、rejected
pending ---> fulfilled 或者 pending ----> rejected
变化不可逆

状态表现:

1. pending状态, 不会出发then和catch
2. fulfilled状态,会触发后续的then回调函数
3. rejected状态,会触发后续的catch回调函数

then 和 catch 改变状态

1. then正常返回fulfilled,里面有报错则返回rejected
2. catch正常返回fulfilled,里面有报错则返回rejected

async/await

async/await 是 js 处理异步操作的现代方法,基于 Promise,但比then/catch更简洁、直观,让代码像 同步代码 一样可读
try..catch 可捕获异常,待体力 Promise 的catch

async

  1. async用于声明一个函数,使其总是返回一个Promise;
  2. 这个Promise的状态由return的值决定:
    1. 如果return一个值,会封装成Promise.resolve(value)
    2. 如果throw一个错误,会封装成Promise.reject(error)

await

  1. await只能在async函数内使用,相当于Promise.then
  2. await 让js 等待Promise解析(fulfilled)后,才继续执行
  3. await 暂停当前函数的执行(包含同层级后面的代码,是指await下面那行的代码),不会阻塞整个线程
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容