異步解決方案的發展歷程

1. 回調函數(callback)異步

setTimeout(() => {
   // callback 函數體
}, 1000)

缺點:回調地獄,不能用 try catch 捕獲錯誤,不能 returnasync

回調地獄的根本問題在於:函數

  • 缺少順序性: 回調地獄致使的調試困難,和大腦的思惟方式不符;性能

  • 嵌套函數存在耦合性,一旦有所改動,就會牽一髮而動全身,即(控制反轉);fetch

  • 嵌套函數過多的多話,很難處理錯誤。ui

優勢:解決了同步的問題(只要有一個任務耗時很長,後面的任務都必須排隊等着,會拖延整個程序的執行)。spa

2. Promise調試

Promise 就是爲了解決 callback 的問題而產生的。code

Promise 實現了鏈式調用,也就是說每次 then 後返回的都是一個全新 Promise,若是咱們在 then 中 return ,return 的結果會被 Promise.resolve() 包裝。blog

優勢:解決了回調地獄的問題

缺點:沒法取消 Promise ,錯誤須要經過回調函數來捕獲

3. Generator

特色:能夠控制函數的執行,能夠配合 co 函數庫使用。自動控制

4. Async/await

async、await 是異步的終極解決方案。

優勢是:代碼清晰,不用像 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 內部實現了generatorgenerator 會保留堆棧中東西,因此這時候 a = 0 被保存了下來

  • 由於 await 是異步操做,後來的表達式不返回 Promise 的話,就會包裝成Promise.reslove(返回值),而後會去執行函數外的同步代碼;

  • 同步代碼執行完畢後開始執行異步代碼,將保存下來的值拿出來使用,這時候 a = 0 + 10

  • 上述解釋中提到了 await 內部實現了 generator,其實 await 就是 generator 加上Promise的語法糖,且內部實現了自動執行 generator。若是你熟悉 co 的話,其實本身就能夠實現這樣的語法糖。

原文地址:https://mp.weixin.qq.com/s/OUeoshYYui9EsB8SC3D6MA

相關文章
相關標籤/搜索