異步、Promise和async-await

異步的科普

我們新銀醫中經常會需要調用異步加載的方法—async-await,但是很多人只是知道可以這麼用,但是不知道爲什麼要這麼用,以及什麼情況下能這麼用,寫這篇文章的目的就是爲了解答這些疑惑,但是由於本人也只是一個小菜鳥,所以有些地方如果不對還請給我指出,這樣我們可以共同進步,那麼我們開始吧。

一、  什麼是異步

異步就是不等任務執行完就執行下一個任務,與之相對的就是同步,它必須等一個任務執行完了才能執行下一個,拿泡茶來類比,異步就是你可以一邊燒水一邊洗茶具,等水燒好了就可以直接泡茶了,同步就是你只能等水燒好了才能去洗茶具然後才能去泡茶,燒水期間不能做別的事情。

由此可以得出兩個結論:第一,需要做兩樣互不干擾的事(比如燒水和洗茶具)的時候,用異步是比較合適的;第二,需要拿到結果才能進行下一件事的時候,必須要用同步,比如說,必須拿到熱水才能泡茶,所以什麼時候用異步是需要好好思考一下環境的。

二、  Promise

Es6中最重要的一個特性,用來解決異步操作中可能會出現的多層回調,將整個函數包裹成一個promise對象,並且規定了promise對象是一個構造函數,統一提供接口,方便使用和維護。

promise出現背景

在promise出現之前,js要想實現異步操作必須使用回調函數得到異步操作的結果,一個兩個還好,如果需要多個異步操作,就會層層嵌套,那麼代碼就會陷入回調地獄裏,非常不利於閱讀和維護。下面就是一個活生生的例子:

所以在es6中推出了promise這樣一個避免回調地獄的實現形式,可以將異步操作以同步操作的流程表達出來,上面這個例子用promise的形式寫出來就是這樣:

這個例子用了promise的鏈式操作方法,相比之下確實容易閱讀。注意:then方法中的return 的作用是把值傳遞到下一個then中。

Promise的特性

①  promise的核心在於“狀態”,總共有三個狀態:pending(正在進行)、resolved(處理完成,通常被叫做fulfilled)和rejected(處理失敗)。

②  這些狀態不受外界影響,當promise被創建時,promise處於pending狀態,當promise裏面的函數調用resolve()就會轉變爲resolved(fulfilled)狀態,如果promise裏面的函數調用reject()則會轉變爲rejected狀態;

③  狀態不可逆,一旦完成了pendingàresolved/rejected的轉換,就不能夠再回到pending狀態;

Promise的用法

Promise的標準裏有以下幾種方法:resolve(),reject(),then(),catch(),all(),race()。這裏有一個小細節需要注意,一旦構建了promise,它就會自動執行,所以通常情況下會把promise包在一個函數裏面,例如:

①  resolve():將promise的狀態修改爲resolved(fulfilled),此時;

②  reject():將promise的狀態修改爲rejected;

③  then(fn1,fn2):

fn1是resolve()的回調方法,而fn2是reject()的回調方法。

Then()方法內通過return 可以返回三種值,第一種是返回一個promise對象;第二種是返回一個同步值;第三種是拋出異常,如果是第一種,則會發生這種情況:

注意:then函數的執行方式是異步的,比如:

這裏執行順序就是①-③-②。

Promise的方法鏈:then方法註冊的回調會依次被調用,每個then方法之間通過return 返回值傳遞參數(請參考promise的例子)此處需注意:用promise的方法鏈的時候,如果其中一個then中有了異常,用catch捕獲後會輸出這樣的異常信息:

這個就是promise令人詬病的地方之一,方法鏈中出了錯,錯誤的堆棧信息並不直觀。

④  catch(fn):用來捕獲和處理promise中的異常,和then(fn1,fn2)中的fn2不同的是,catch()可以捕獲fn1裏面的錯誤,所以推薦用catch()來捕獲和處理異常。

⑤  all([fn1,fn2,fn3…]):使fn1,fn2,fn3等函數全部都執行完了再一起輸出結果,且fn1,fn2,fn3等函數是同時執行的。

⑥  race([fn1,fn2,fn3…]): fn1,fn2,fn3等函數誰先執行完(他們是同時執行的)就輸出誰的結果,此處需要注意的是,輸出結果後,流程繼續往下走,但是fn2,fn3等函數仍然在執行。

三、  Async-await

async是es8中出現的,被很多人稱之爲異步的終極解決方法。瞭解promise之後,才能瞭解async,因爲async是基於promise的語法糖,包裹了async的函數會隱式的返回一個promise對象,await可以將其後的代碼轉化爲同步的原因是因爲await本質上就是把其後的代碼包裹在promise的then函數中強制代碼按照順序執行,所以await必須寫在async函數裏面.

Async-await PK promise

1、代碼簡潔,語法優美。相比於promise來說async的代碼更加容易看懂,還是拿promise中第一個例子,用async來寫的話是這樣:

2、異常堆棧信息清晰易懂。

3、異步的概念更加弱化,同步異步之間的轉換更方便。

Async-await特性

1、Await只會影響直接包裹它的async函數,舉個反面例子:

就會報錯:

2、await 命令後面,可以跟 Promise 對象(使用了async-await的函數也是promise對象),和原始類型的值(數值、字符串和布爾值,但這時等同於同步操作)。

3、命令後面的 Promise 對象,運行結果可能是 rejected,所以最好把 await 命令放在 try...catch 代碼塊中,也可以用promise自帶的catch()來捕獲和處理異常,如下:

Async-await的用法

使用方法:在需要等待的異步代碼前面加上await,在直接包含await的方法前面加async;

擴展用法:可以在添加了async的函數後面添加then()方法進行回調,promise的方法async都能用


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章