Promise和await中的异步操作
Promise中的异步操作:
- 基于then传递的 onfulfilled/onrejected 方法的执行是异步的
- 哪怕执行 then 的时候,已经知道实例的状态和值了,也不会把 onfulfilled/onrejected 立即执行
- 把其加入到 WebAPI 中监听「只不过已经确定了实例的状态,对应的方法是可以执行的」
- 紧接着把其放到 EventQueue 的异步微任务队列中 排队等待执行!!
- 等待同步代码执行完毕,主线程空闲下来了,把异步任务队列中的方法拿出来依次执行…
所以本质上,Promise中真正的异步操作是其原型上的then方法
由此可改进我们自己写的Promise源码中的then方法部分,因为我们的方法是基于兼容IE写的,所以采用的方法的用定时器不设时间或设置时间为0处理then方法中的代码(以及Promise源码中处理then传递的存起来的回调函数集合的执行),ES6中新增了一种方法用来创建一个异步的微任务:
queueMicrotask(() => {// 创建一个异步的微任务})
- await 中的异步操作
- 遇到 await ,立即把其下面的代码(当前上下文)放到 WebAPI 中监听「异步的微任务」
- 再看 await 后面的实例是成功还是失败,如果是成功(可能要等一段时间),则说明此 微任务 可以执行,再把其放到 EventQueue 排队等待执行
- 最后也是同步的都处理完毕了,才会把异步的拿过来处理
举个栗子
executor 函数的执行是同步的
let p1 = new Promise((resolve) => {
// executor 函数的执行是同步的
console.log(1)
resolve(100) // 修改实例的状态和值是同步的
console.log(2)
})
console.log(3, p1)
//==>1 2 3
使用到then才是异步
let p1 = new Promise(resolve => {
resolve(100)
})
p1.then(value => {
console.log('成功:', value) //再输出'成功: 100'
})
console.log('OK') //先输出'OK'
let p1 = new Promise(resolve => {
setTimeout(() => {
console.log(1) //@1
resolve(100) //立即把实例的状态改为成功,值是100;通知集合中的方法执行的时候,不是让其立即执行,而是异步通知执行!!
console.log(2) //@2
}, 2000)
})
p1.then(value => {
console.log('成功:', value) //@3
})
const fn = async () => {
console.log(1) //@1
await Promise.resolve(0)
console.log(2) //@3
}
fn()
console.log(3) //@2
//执行到await时 其同一上下文中 下面的代码会以微任务形式存在WebAPI中,因为是立即知道状态为成功状态,所以直接放入EventQueue的异步微任务队列中等待同步任务执行结束,浏览器空闲下来后去队列中找到这个任务并执行
练习题
第一个
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1()
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('promise2')
})
console.log('script end')
第二个
let body = document.body//记得给body和html同时设置宽高 不然点不到
body.addEventListener('click', function () {
Promise.resolve().then(() => {
console.log(1)
})
console.log(2)
})
body.addEventListener('click', function () {
Promise.resolve().then(() => {
console.log(3)
})
console.log(4)
})
![BIME8LD27)6OH3RU24AK_X_tmb.jpg