XiaoChengyin / blog

https://github.com/XiaoChengyin/blog
MIT License
0 stars 0 forks source link

Promise 和 async/await #4

Open XiaoChengyin opened 4 years ago

XiaoChengyin commented 4 years ago

Promise 和 async/await

事件循环和消息队列

消息队列是一个先进先出的队列,队列中存有需要执行的任务。事件循环是指每当主线程任务执行完毕后会从消息队列中取出下一个要执行的任务。

微任务和宏任务

所有异步任务可以分为两类,即宏任务和微任务。微任务的优先级大于宏任务,当宏任务执行完毕后会立即执行微任务队列中的所有任务,直到当前微任务队列为空时才会执行下一个宏任务。

宏任务:I/OsetTimeoutsetIntervalsetImmediaterequestAnimationFrame。 微任务:process.nextTickMutationObserverPromise#then/catch/finally

Promiseasync 函数

async/await 只是 Promise 的语法糖,原理与 Promise 是一样的,所以 async 也属于微任务。一个 async 函数就可以理解为一个 Promiseawait 之前的代码相当于 Promise 的回调函数,都是立即执行的同步代码;await 语句相当于 Promise 中的子 Promise,父 Promise 想要 resolve 必须等子 Promiseresolve 才行;await 后面的代码相当于父 Promise.then 中的回调函数,即子 Promise resolve 之后才执行父 Promise.then 中的代码。

举个例子:

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')

输出结果为:

'script start'
'async1 start'
'async2'
'promise1'
'script end'
'promise2'
'async1 end'
'setTimeout'

把 async 函数改写成 Promise 能够的到相同的结果

function async2() {
    return new Promise((resolve, reject) => {
        console.log('async2')
        resolve()
    })
}
// chrome 71
function async1(){
    console.log('async1 start');
    const p = async2();
    return new Promise((resolve) => {
        Promise.resolve().then(() => {
            p.then(resolve)
        })
    }).then(() => {
        console.log('async1 end')
    });
}
// chrome 73
// 优化后 async 的执行更快,
// `async1 end` 能够在 `promise2` 之前输出
function async1(){
    console.log('async1 start');
    const p = async2();
    return Promise.resolve(p).then(() => {
        console.log('async1 end')
    });
}

Promise.resolve(p)new Promsie((resolve) => resolve(p)) 的差异

当 p 是一个 promise 时,第一种写法会直接返回 p,而第二种写法会创建额外的微任务。因为这时的 p 是一个 thenable 对象,在 Promise 中 resolve 一个 thenable 对象需要通过 PromiseResolveThenableJob 进行转换,而这是一个微任务。

XiaoChengyin commented 4 years ago

如何将async函数改为Promise写法(完整版)

async function a1() {
    console.log('start')
    let a2result = await a2()
    console.log(a2result)
    let a3result = await a3(a2result)
    console.log(a2result)
    return a3result
}

// chrome 71
function aa1() {
    console.log('start')
    return new Promise(resolve => {
        a2().then(resolve)
    }).then(a2result => {
        console.log(a2result)
        return new Promise(resolve => {
            a3(a2result).then(resolve)
        }).then(a3result => {
            console.log(a2result)
            return new Promise(resolve => {
                resolve(a3result)
            })
        })
    })
}

// chrome 72
function aaa3() {
    console.log('start')
    return Promise.resolve(a2()).then(a2result => {
        console.log(a2result)
        return Promise.resolve(a3(a2result)).then(a3result => {
            console.log(a2result)
            return Promise.resolve(a3result)
        })
    })
}

// Promise.resolve 原理
Promise.resolve = function(value) {
    if (value instanceof Promise) return value
    return new Promise(resolve => resolve(value))
}