1.消息队列-宏任务
回调函数类型
同步回调
函数内部执行
function a(){console.log("11")}
function b(fun) { //这里b执行的a方法是同步回调方法
fun()
}
a()
异步回调
函数外执行,基于消息队列触发执行
function a(){console.log("11")}
settimeout( a,1000)//这里settimeout 执行的a方法是异步回调方法
消息队列
可以理解为一个死循环,不断读取任务并执行
异步回调流程
- XMLHttpRequest
- 主线程在js代码发起XMLHttpRequest 请求,通过IPC通知网络进程下载
- 网络进程不断读取服务端返回的数据,每次接收信息都会把回调函数加入 消息队列。(包含字节大小等)
- 事件循环依次读取宏任务,开发可以根据是下载的回调,做响应的处理
- 当下载结束也会写入 下载完成的任务到消息队列,开发可以在回调中处理完成逻辑
- setTimeout
- 生成回调任务添加到消息队列
- 消息队列依次读取宏任务执行
2.微任务
优势
解决宏任务颗粒度不够细问题,可以更加精准控制任务执行的顺序
js主线程执行过程
- 主要组成
- 调用栈
- 主线程
- 消息队列
- 流程
- 主线程一直循环 读取 消息队列宏任务,每执行完一个宏任务,都把当前生成的微任务清空掉,挨个执行。
微任务执行时机
在当前主函数 执行析构函数时
嵌套调用问题
- 同步回调
- 会导致栈溢出,因为都在同一个宏任务中执行函数,栈会不断嵌套累加
fun(){
console.log("111")
fun()
}
fun()
- settimout
- 回调函数是基于消息队列,下一个宏任务调用时,上一个宏任务已经完全执行完,栈已被清空
fun(){
console.log("111")
}
settimeout(fun)
- Promise.then()
- 虽然不会提示栈溢出,但是会卡死,因为执行完宏任务,都会清空执行所有微任务,清空时微任务已经清空所有调用栈
- 但是嵌套再调用微任务又会继续生成微任务队列,并执行。导致下一个宏任务一直无法开始
function fun() {
console.log("111")
Promise.resole().then(fun)
}
fun()
MutationObserver的工作原理
- 生成微任务,不会阻塞主程序执行
- 多个事件监听只触发一次,并且返回数组来描述不同的变化事件
- 通过options参数传入指定的监听类型
3.协程-async-await
地狱回调
- XMLHttpRequest有很多注册的回调方法,代码阅读时顺序是错乱的
- 编码线性问题
- promise方案
- 大量的promise.then(),then()依然导致阅读困难,语义化不明显
- 协程+ Generator + co执行器 + promise方案
- 实现的函数的暂停和恢复执行,但是引入太多臃俞的代码
- async await
- 代码最直观线性
- promise方案
协程
- 协程是运算在线程上的多个任务
- 1个线程包含多个协程
- 一个线程只能同时运行一个协程
- A启动B,A就是B的父协程
例子
function* getResult() {
console.log(1111)
yield '11'
console.log(2222)
yield '22'
console.log(3333)
return '33'
}
let result = getResult()
console.log(result.next().value)
console.log(result.next().value)
console.log(result.next().value)
async await
例子
async function main(){
let a = await Promise.resolve("111")
console.log(a)
console.log("222")
}
main()
console.log("333")
// 输出
// 333 //因为最外面的代码没有被包裹 async,依然不会被等待
// 111
// 222
原理
- 被async包裹的函数会被异步执行,可以理解方法已经变成 Generator函数 带*
- async函数里使用 await,等价于调用了yield '11',把当前协程挂起,并执行await后面的异步代码
- 等待异步代码返回resolve成功后,会自动执行next() 交回给当前协程继续执行代码
async
异步执行并隐式返回 Promise
await
- 后面支持一个返回promise对象
- 可以是非promise对象或为空,系统会自动包裹一个Promise.resolve()