JS 異步已經告一段落了,這裏來一波小總結ajax
setTimeout(() => { // callback 函數體 }, 1000)
缺點:回調地獄,不能用 try catch 捕獲錯誤,不能 return異步
回調地獄的根本問題在於:async
ajax('XXX1', () => { // callback 函數體 ajax('XXX2', () => { // callback 函數體 ajax('XXX3', () => { // callback 函數體 }) }) })
優勢:解決了同步的問題(只要有一個任務耗時很長,後面的任務都必須排隊等着,會拖延整個程序的執行。)函數
Promise就是爲了解決callback的問題而產生的。性能
Promise 實現了鏈式調用,也就是說每次 then 後返回的都是一個全新 Promise,若是咱們在 then 中 return ,return 的結果會被 Promise.resolve() 包裝fetch
優勢:解決了回調地獄的問題spa
ajax('XXX1') .then(res => { // 操做邏輯 return ajax('XXX2') }).then(res => { // 操做邏輯 return ajax('XXX3') }).then(res => { // 操做邏輯 })
缺點:沒法取消 Promise ,錯誤須要經過回調函數來捕獲調試
特色:能夠控制函數的執行,能夠配合 co 函數庫使用code
function *fetch() { yield ajax('XXX1', () => {}) yield ajax('XXX2', () => {}) yield ajax('XXX3', () => {}) } let it = fetch() let result1 = it.next() let result2 = it.next() let result3 = it.next()
async、await 是異步的終極解決方案blog
優勢是:代碼清晰,不用像 Promise 寫一大堆 then 鏈,處理了回調地獄的問題
缺點:await 將異步代碼改形成同步代碼,若是多個異步操做沒有依賴性而使用 await 會致使性能上的下降。
async function test() { // 如下代碼沒有依賴性的話,徹底可使用 Promise.all 的方式 // 若是有依賴性的話,其實就是解決回調地獄的例子了 await fetch('XXX1') await fetch('XXX2') await fetch('XXX3') }
下面來看一個使用 await
的例子:
let a = 0 let b = async () => { a = a + await 10 console.log('2', a) // -> '2' 10 } b() a++ console.log('1', a) // -> '1' 1
對於以上代碼你可能會有疑惑,讓我來解釋下緣由
b
先執行,在執行到 await 10
以前變量 a
仍是 0,由於 await
內部實現了 generator
,generator
會保留堆棧中東西,因此這時候 a = 0
被保存了下來await
是異步操做,後來的表達式不返回 Promise
的話,就會包裝成 Promise.reslove(返回值)
,而後會去執行函數外的同步代碼a = 0 + 10
上述解釋中提到了 await
內部實現了 generator
,其實 await
就是 generator
加上 Promise
的語法糖,且內部實現了自動執行 generator
。若是你熟悉 co 的話,其實本身就能夠實現這樣的語法糖。