與Promise血脈相連的async/await

async/await是JavaScript爲了解決異步問題而提出的一種解決方案,許多人將其稱爲異步的終極解決方案。JavaScript的發展也經歷了回調、Promise、async/await三個階段,本篇文章記錄了我本身對於async/await的理解。由於async/await的使用離不開Promise,若是對於Promise不熟悉的話,能夠看下這篇介紹:前端萌新眼中的Promise及使用前端

1、async/await的具體使用規則

在咱們處理異步的時候,比起回調函數,Promise的then方法會顯得較爲簡潔和清晰,可是在處理多個彼此之間相互依賴的請求的時候,就會顯的有些累贅。這時候,用async和await更加優雅,後面會詳情說明。程序員

async/await使用規則一:凡是在前面添加了async的函數在執行後都會自動返回一個Promise對象編程

例子:promise

async function test() {
    
}

let result = test()
console.log(result)  //即使代碼裏test函數什麼都沒返回,咱們依然打出了Promise對象
複製代碼

async/await使用規則二:await必須在async函數裏使用,不能單獨使用bash

錯誤的例子:dom

function test() {
    let result = await Promise.resolve('success')
    console.log(result)
}

test()   //執行之後會報錯
複製代碼

正確的例子:異步

async test() {
    let result = await Promise.resolve('success')
    console.log(result)
}
test()
複製代碼

async/await使用規則三:await後面須要跟Promise對象,否則就沒有意義,並且await後面的Promise對象沒必要寫then,由於await的做用之一就是獲取後面Promise對象成功狀態傳遞出來的參數。async

正確的例子:函數

function fn() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('success')
        })
    })
}

async test() {
    let result = await fn() //由於fn會返回一個Promise對象
    console.log(result)    //這裏會打出Promise成功後傳遞過來的'success'
}

test()
複製代碼

沒有意義的例子(不會報錯):post

async test() {
    let result = await 123
    console.log(result)
}

test()
複製代碼

2、async/await的錯誤處理方式

關於錯誤處理,如規則三所說,await能夠直接獲取到後面Promise成功狀態傳遞的參數,可是卻捕捉不到失敗狀態。在這裏,咱們經過給包裹await的async函數添加then/catch方法來解決,由於根據規則一,async函數自己就會返回一個Promise對象。

一個包含錯誤處理的完整的async/await例子:

let promiseDemo = new Promise((resolve, reject) => {
    setTimeout(() => {
        let random = Math.random()
        if (random >= 0.5) {
            resolve('success')
        } else {
            reject('failed')
        }   
    }, 1000)
})

async function test() {
    let result = await promiseDemo
    return result  //這裏的result是promiseDemo成功狀態的值,若是失敗了,代碼就直接跳到下面的catch了
}

test().then(response => {
    console.log(response) 
}).catch(error => {
    console.log(error)
})

複製代碼

上面的代碼須要注意兩個地方,一是async函數須要主動return一下,若是Promise的狀態是成功的,那麼return的這個值就會被下面的then方法捕捉到;二是,若是async函數有任何錯誤,都被catch捕捉到!

3、同步與異步

在async函數中使用await,那麼await這裏的代碼就會變成同步的了,意思就是說只有等await後面的Promise執行完成獲得結果纔會繼續下去,await就是等待,這樣雖然避免了異步,可是它也會阻塞代碼,因此使用的時候要考慮周全。

好比下面的代碼:

function fn(name) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(`${name}成功`)
        }, 1000)
    })
}

async function test() {
    let p1 = await fn('小紅')
    let p2 = await fn('小明')
    let p3 = await fn('小華')
    return [p1, p2, p3]
}

test().then(result => {
    console.log(result)
}).catch(result => {
    console.log(result)
})
複製代碼

這樣寫雖然是能夠的,可是這裏await會阻塞代碼,每一個await都必須等後面的fn()執行完成纔會執行下一行代碼,因此test函數執行須要3秒。若是不是遇到特定的場景,最好仍是不要這樣用。

3、一個小測試

寫到這裏,忽然想起Promise的代碼執行順序也是挺須要注意的。

請看下面的代碼,執行完之後打出的數字的順序是怎樣的呢?

console.log(1)
let promiseDemo = new Promise((resolve, reject) => {
    console.log(2)
    setTimeout(() => {
        let random = Math.random()
        if (random >= 0.2) {
            resolve('success')
            console.log(3)
        } else {
            reject('failed')
            console.log(3)
        }   
    }, 1000)
})

async function test() {
    console.log(4)
    let result = await promiseDemo
    return result
}

test().then(result => {
    console.log(5)
}).catch((result) => {
    console.log(5)
})

console.log(6)
複製代碼

答案是:1 2 4 6 3 5

4、一個適合使用async/await的業務場景

在前端編程中,咱們偶爾會遇到這樣一個場景:咱們須要發送多個請求,而後面請求的發送老是須要依賴上一個請求返回的數據。對於這個問題,咱們既能夠用的Promise的鏈式調用來解決,也能夠用async/await來解決,然然後者會更簡潔些。

使用Promise鏈式調用來處理:

function request(time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(time)
        }, time)
    })
}

request(500).then(result => {
    return request(result + 1000)
}).then(result => {
    return request(result + 1000)
}).then(result => {
    console.log(result)
}).catch(error => {
    console.log(error)
}) 
複製代碼

使用async/await的來處理:

function request(time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(time)
        }, time)
    })
}

async function getResult() {
    let p1 = await request(500)
    let p2 = await request(p1 + 1000)
    let p3 = await request(p2 + 1000)
    return p3
}

getResult().then(result => {
    console.log(result)
}).catch(error => {
    console.log(error)
})
複製代碼

相對於使用then不停地進行鏈式調用, 使用async/await會顯的更加易讀一些。

5、在循環中使用await

若是在是循環中使用await,就須要牢記一條:必須在async函數中使用

for...of中使用await:

let request = (time) => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(time)
        }, time)
    })
}

let times = [1000, 500, 2000]
async function test() {
    let result = []
    for (let item of times) {
        let temp = await request(item)
        result.push(temp)
    }
    return result
}

test().then(result => {
    console.log(result)
}).catch(error => {
    console.log(error)
})
複製代碼

上面就是我今天關於async/await理解的記錄,筆者做爲一隻程序員生活只有半年,以上內容估計還有錯誤之處,若是掘金上的朋友有看到,還望不吝指出!謝謝您的觀看!

相關文章
相關標籤/搜索