async/await是JavaScript爲了解決異步問題而提出的一種解決方案,許多人將其稱爲異步的終極解決方案。JavaScript的發展也經歷了回調、Promise、async/await三個階段,本篇文章記錄了我本身對於async/await的理解。由於async/await的使用離不開Promise,若是對於Promise不熟悉的話,能夠看下這篇介紹:前端萌新眼中的Promise及使用。前端
在咱們處理異步的時候,比起回調函數,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()
複製代碼
關於錯誤處理,如規則三所說,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捕捉到!
在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秒。若是不是遇到特定的場景,最好仍是不要這樣用。
寫到這裏,忽然想起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
在前端編程中,咱們偶爾會遇到這樣一個場景:咱們須要發送多個請求,而後面請求的發送老是須要依賴上一個請求返回的數據。對於這個問題,咱們既能夠用的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會顯的更加易讀一些。
若是在是循環中使用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理解的記錄,筆者做爲一隻程序員生活只有半年,以上內容估計還有錯誤之處,若是掘金上的朋友有看到,還望不吝指出!謝謝您的觀看!