原文git
以前總結了關於 JavaScript 異步的 事件循環與消息隊列 機制以及 ES6 帶來的 微任務與宏任務 的知識。傳送門github
下面是關於JS異步處理的各類方案:ajax
callback >> ES6 Primise >> async/await
複製代碼
先看一段代碼:bash
// 假設有一個耗時的異步請求 ajax,在 2 秒後打印日誌
function ajax () {
// do something...
setTimeout(() => {
console.log('Hello, Zavier Tang!')
}, 2000)
}
ajax()
// do something...
console.log('The end.')
// The end.
// Hello, Zavier Tang!
複製代碼
這裏模擬了一個簡單的異步網絡請求,並在 2 秒後打印 "Hello, Zavier Tang!",而後作一些處理("do something")後,打印結束 "The end."。網絡
結果是先打印的 "The end."。異步
顯然這並非咱們要的結果,"異步請求" ajax
中的 setTimeout
並無阻塞代碼的執行,而是直接執行了 console.log()
。async
一樣是上面的異步網絡請求,這裏使用 callback 回調函數的方式解決 JavaScript 同步帶來的問題。函數
function ajax (fn) {
// do something...
setTimeout(() => {
console.log('Hello, Zavier Tang!')
fn()
}, 2000)
}
ajax(() => {
// do something...
console.log('The end.')
})
// Hello, Zavier Tang!
// The end.
複製代碼
這裏咱們直接把異步請求以後要作的一些操做作爲回調函數,傳遞到 ajax 中去,並在異步請求結束後執行回調函數裏的操做。post
問題彷佛已經解決了??可是,若是有多個異步請求,而且在每一個異步請求完成後都執行一些操做,那代碼就會像下面這樣:學習
function ajax (fn) {
// do something...
setTimeout(() => {
console.log('Hello, Zavier Tang!')
fn()
}, 500)
}
ajax(() => {
// do something...
console.log('The end 1.')
ajax(() => {
// do something...
console.log('The end 2.')
ajax(() => {
// do something...
console.log('The end 3.')
ajax(() => {
// do something...
console.log('The end 4.')
ajax(() => {
// do something...
console.log('The end 5.')
// ......
// ......
})
})
})
})
})
// Hello, Zavier Tang!
// The end 1.
// Hello, Zavier Tang!
// The end 2.
// Hello, Zavier Tang!
// The end 3.
// Hello, Zavier Tang!
// The end 4.
// Hello, Zavier Tang!
// The end 5.
複製代碼
看起來很嚇人!!
若是是這樣:請求1結束後進行請求2,而後還有請求三、請求四、請求5,而且請求2還可能依賴於請求1的數據,請求3依賴於請求2的數據,不停的一層一層嵌套,對於錯誤的處理也極不方便,因此稱之爲 callback 回調地獄。
ES6 的 Promise 被稱爲 JS 異步的下一代解決方案。
關於 Promise:
接下來使用 Promise 處理異步:
function ajax (word) {
return new Promise((resolve) => {
// do something...
setTimeout(() => {
resolve('Hello ' + word)
}, 500)
})
}
ajax('請求1')
.then((word) => {
console.log(word)
console.log('The end 1.')
return ajax('請求2')
})
.then((word) => {
console.log(word)
console.log('The end 2.')
return ajax('請求3')
})
.then((word) => {
console.log(word)
console.log('The end 3.')
})
// .catch(() => {})
// Hello 請求1
// The end 1.
// Hello 請求2
// The end 2.
// Hello 請求3
// The end 3.
複製代碼
上面仍是連續的異步請求,每次請求後打印日誌。這樣看起來比上面的回調地獄舒服多了,每一個請求經過鏈式的調用,在最後能夠對全部的請求進行錯誤處理。
但,彷佛還並非特別優雅。
關於 async/await 的簡介:
體驗一下神奇的 async/await:
// 接上面的代碼
async function doAsync () {
const word1 = await ajax('請求1')
console.log(word1)
console.log('The end 1')
const word2 = await ajax('請求2')
console.log(word2)
console.log('The end 2')
const word3 = await ajax('請求3')
console.log(word3)
console.log('The end 3')
}
doAsync()
// Hello 請求1
// The end 1
// Hello 請求2
// The end 2
// Hello 請求3
// The end 3
複製代碼
這樣看起來,更優雅了。沒有任何括號,也沒有 callback,沒有 then,直接申明 async,使用 await 等待異步執行完成,看起來也更像是同步的代碼。
JavaScript 的異步編寫方式,從 callback 回調函數到 Promise ,再到 async/await,只能說。。。
技術發展太快啦,趕忙學習吧!