前言
本篇博文出至於我的
github
倉庫:web-study,如果你覺得對你有幫助歡迎star,你們的點贊是我持續更新的動力,謝謝!
非同步程式設計在前端開發中尤為常見,從最早的XHR
,到後來的各種封裝ajax
,再到DOM
事件觸發的回撥,無不涉及非同步程式設計。今天我們們來聊聊ES6
中新提出的非同步解決方案:Promise
和async/await
。
- Promise的原理和基本用法
- Promise的原理
Promise 是一種對非同步操作的封裝,可以通過獨立的介面新增在非同步操作執行成功、失敗時執行的方法。主流的規範是 Promises/A+。
Promise中有幾個狀態:
* pending: 初始狀態, 非 fulfilled 或 rejected;
* fulfilled: 成功的操作,為表述方便,fulfilled 使用 resolved 代替;
* rejected: 失敗的操作。
pending可以轉化為fulfilled或rejected並且只能轉化一次,也就是說如果pending轉化到fulfilled狀態,那麼就不能再轉化到rejected。並且fulfilled和rejected狀態只能由pending轉化而來,兩者之間不能互相轉換。
- Promise的基本用法
Promise是一個建構函式,自己身上有all、reject、resolve這幾個眼熟的方法,原型上有then、catch等同樣很眼熟的方法。
resolve
的用法var p = new Promise(function(resolve, reject){ //做一些非同步操作 setTimeout(function(){ resolve('隨便什麼資料'); }, 2000); }) p.then(res => { console.log(res) // '隨便什麼資料' })
Promise的建構函式接收一個引數,是函式,並且傳入兩個引數:resolve,reject,分別表示非同步操作執行成功後的回撥函式和非同步操作執行失敗後的回撥函式。其實這裡用“成功”和“失敗”來描述並不準確,按照標準來講,resolve是將Promise的狀態置為fullfiled,reject是將Promise的狀態置為rejected。
在上面的程式碼中,我們執行了一個非同步操作,也就是setTimeout
,2秒後,並且呼叫resolve方法,表示非同步操作執行成功。
reject
的用法
javascript var p = new Promise(function(resolve, reject){ //做一些非同步操作 setTimeout(function(){ reject('隨便什麼資料'); }, 2000); }) p.catch(err => { console.log(err) // '隨便什麼資料' })
上面我們在非同步操作中呼叫了reject
方法,也就是說把Promise的狀態由pending
轉換到了fulfilled
狀態,最後可以通過Promise例項物件的catch()
方法獲取非同步資料。
- Async/Await簡介與用法
非同步操作是 JavaScript 程式設計的麻煩事,很多人認為async函式是非同步操作的終極解決方案。
- Async/Await簡介
async/await是寫非同步程式碼的新方式,優於回撥函式和Promise。
async/await是基於Promise實現的,它不能用於普通的回撥函式。
async/await與Promise一樣,是非阻塞的。
async/await使得非同步程式碼看起來像同步程式碼,再也沒有回撥函式。但是改變不了JS單執行緒、非同步的本質。
- Async/Await的用法
使用await,函式必須用async標識
await後面跟的是一個Promise例項或者是其他的任意js表示式(意義不大)
var fun = async () => {
let result = await Promise.resolve(123)
console.log(result)
}
fun() // 123
await
等待的雖然是promise物件,但是不用呼叫.then()方法就能直接得到返回值。
- Async/Await的應用
Promise
雖然一方面解決了callback
的回撥地獄,但是相對的把回撥“縱向發展”了,形成了一個回撥鏈。example:
function sleep(wait) {
return new Promise((res,rej) => {
setTimeout(() => {
res(wait)
},wait)
})
}
/*
let p1 = sleep(100)
let p2 = sleep(200)
let p =*/
sleep(100).then(result => {
return sleep(result + 100)
}).then(result02 => {
return sleep(result02 + 100)
}).then(result03 => {
console.log(result03)
})
控制檯輸出:
300
後面的結果都是依賴前面的結果。
改成async/await寫法就是:
async function demo() {
let result01 = await sleep(100)
//上一個await執行之後才會執行下一句
let result02 = await sleep(result01 + 100)
let result03 = await sleep(result02 + 100)
// console.log(result03);
return result03
}
demo().then(result => {
console.log(result)
})
因為async返回的也是promise物件,所以用then接受就行了。
結果:
300
需要注意的就是 await
是強制把非同步變成了同步,這一句程式碼執行完,才會執行下一句。