ES6之async await


含義

  • 內置執行器
    • Generator函數的執行必須靠執行器,所以才有了co模塊,而async函數自帶執行器。也就是說,async函數的執行,與普通函數一模一樣,只要一行fn()
  • 更好的語義
    • async和await,比起星號和yield,語義更清除了。async表示函數里又異步操作,await表示緊跟在后面的表達式需要等待結果。
  • 更廣的適用性
    • co模塊規定,yield命令后面只能時Thunk函數或Promise對象,而async函數的await命令后面,可不是Promise對象和原始類型的值(數值、字符串和布爾值,但這時會自動轉成立即resolved 的Promise對象)
  • 返回值時Promise
    • async函數的返回值時Promise對象,這比Generator函數的返回值是Iterator對象方便多了。你可以用then方法制定下一步操作。

進一步說,async函數完全可以看作多個異步操作,包裝成的一個Promise對象,而await命令就是then方法的語法糖

基本用法

async函數返回一個Promise對象,可以使用then方法添加回調函數。當函數執行的時候,一旦遇到await就會先返回,等到異步操作完成,在接着執行函數體后面的語句

    async function fn(){
        console.log(4)
        let f1 = await Promise.resolve(1)
        console.log(f1) // 1
        let f2 = await Promise.resolve(2)
        return f2
    }
    fn().then(res=>{
        console.log(res) // 2
    })
    console.log(3)
    // 4  3  1  2

上面代碼中,函數前面的async關鍵字,表示函數內部有異步操作。調用該函數時,會立即返回一個Promise對象。

    function timeout(ms){
        return new Promise((resolve)=>{
            setTimeout(resolve,ms)
        })
    }
    async function fn(value,ms){
        await timeout(ms)
        console.log(value)
    }
    fn('haha',3000)

上面代碼會在3秒后輸出haha

async函數有多種使用形式。

    // 函數聲明
    async function fn(){}
    // 函數表達式
    let fn1 = async function(){}
    // 對象的方法
    let obj = {async foo(){}}
    obj.foo().then(()=>console.log(111)) // 111
    // class 的方法
    class fn2{
        constructor(name){
            this.name = name;
        }
        async getName(){
            return this.name
        }
    }
    let name = new fn2('小明');
    name.getName().then(res=>console.log(res)) // 小明

語法

async函數返回一個Pormise對象。
async函數內部return語句返回的值,會成為then方法回調函數的參數

    let fn = async function(){
        return 111
    }
    fn().then(res=>{console.log(res)}) // 111

上面代碼,函數fn返回的值,會被then放回回調函數接收到

async內部拋出錯誤,會導致返回的Promise對象變為reject狀態。拋出的錯誤對象會被catch方法回調函數接收到。

    let fn = async function(){
        throw new Error('出錯了')
    }
    fn().catch(error=>{
        console.log(error); // Error: 出錯了
    })
Promise對象的狀態變化

async函數返回的Promise對象,碧璽等到內部所有await命令后面的Promise對象執行完,才會發生狀態改變,除非遇到return語句或者拋出錯誤。也就是說,只有asunc函數內部的異步操作執行完,才會執行then方法指定的回調函數。

    let fn = async function(){
        await new Promise((resolve)=>{
            setTimeout(resolve,3000)
        })
        await new Promise((resolve)=>{
            setTimeout(resolve,3000)
        })
        return 1
    }
    fn().then(res=>{
        console.log(res);
    })

上面代碼,then回調函數會在6秒之后輸出res

await

正常情況下,await命令后面是一個Promise對象,返回該對象的結果。如果不是Promise對象,就直接返回對應的值

    let fn = async function(){
        // 等同於
        // return 1
        return await 1
    }
    fn().then(res=>{
        console.log(res); // 1
    })

上面代碼中,await命令的參數是數值1,這是等同於return 1

    let fn = async ()=>{
        await Promise.reject('出錯了')
    }
    fn().catch(error=>{console.log(error)}) // 出錯了

注意:上面代碼中,await語句前面沒有return,但是reject方法的參數依然傳入了catch方法的回調函數。這里如果在await前面加上return,效果是一樣的

注意:任何一個await語句后面的Promise對象變為reject,那么整個async函數都會中斷執行

有時,我們希望即使前一個異步操作失敗,也不要中斷后面的異步操作。這時可以將第一個await放在try...catch結構里面,這樣不管這個異步操作是否成功,第二個await都會執行

    let fn = async ()=>{
        try{
            await Promise.reject('出錯了')
        }catch(error){
            console.log(error) 
        }
        return 1
    }
    fn().then(res=>console.log(res)) // 1

另一種寫法

    let fn = async ()=>{
        await Promise.reject('出錯了').catch(error=>{
            console.log(error) 
        })
        return 1
    }
    fn().then(res=>console.log(res)) // 1

錯誤處理

如果await后面的異步操作出錯,那么等同於async函數返回的 Promise 對象被reject。

    let fn = async ()=>{
        await Promise.reject('出錯了')
        return 1
    }
    fn()
    .then(res=>console.log(res))
    .catch(error=>{
        console.log(error) // 出錯了
    })

上面代碼中,函數fn執行后,await后面的Promise對象拋出了一個錯誤對象,導致catca方法的回調函數被調用。

防止出錯的方法,也是將其放在try...catch代碼塊中

    let fn = async ()=>{
        try{
            await Promise.reject('出錯了')
        }catch(error){
            console.log(error);
        }
        return 1
    }
    fn()
    .then(res=>console.log(res)) // 1

如果有多個await命令,可以統一放在try...catch


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM