一步一步實現一個符合PromiseA+規範的Promise庫(1)

xjylyh發表於2018-03-26

今天我們來自己手寫一個符合PromiseA+規範的Promise庫。大家是不是很激動呢??

clipboard.png

才沒有。。 我們都知道。在現在的前端開發中,Promise這個東西基本上所有的開發中都會用到。

那必然有些萌新就會問了,Promise到底是個什麼東西呢。

按照規範來說。Promise是非同步程式設計的一種解決方案,比傳統的解決方案——回撥函式和事件——更合理和更強大。它由社群最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise物件。

通俗來講。。這個東西就是為了解決我們平常的回撥函式,避免回撥地獄的一種解決方案。所以說這個東西大家不僅要會用哦,還應該知道他的一些原理。so,我們一起來實現下吧。

clipboard.png

接下來我們先看一個簡單的Promise。

clipboard.png

這個就是es6標準中的Promise。我們可以看到,其實Promise就是一個建構函式。

這個建構函式中只有一個引數。這個引數在Promise/A+規範中被稱為executor(執行者..我覺得叫執行器蠻好)。

因為這個執行器是為了執行後面的resolve(決定)和reject(拒絕)方法。呃...其實你可以把resolve看作是成功,把reject看做失敗。

當然了我們還可以根據自己定義的規則來進行Promise中resolve和reject的呼叫,不過這是用法,我們這裡就當大家會用了。。

clipboard.png

然後我們可以看到,在建構函式的例項p中還有一個then方法。這裡我們就要想了,既然是建構函式的例項上哪必然這個函式是掛在到這個建構函式的原型上。

還有很重要的一點就是我們可以想一下,在Promise中這個Promise的當前狀態是一個問題。在A+規範中規定:一個Promise只有三種狀態,我們看圖

clipboard.png

什麼意思呢。。

大致的意思就是說,一個Promise有且僅有(pending->等待,fulfilled->已執行,rejected->已拒絕)這三種狀態中的一種(ps:我曾經看到過一個詞->懸而未決用來形容pending也不錯 :)。

我們知道了這些,接下來我們就來手動實現一個簡單的。

clipboard.png

繼續。。。。

clipboard.png

這裡我們要說一下,貌似剛才忘說了。。。

clipboard.png

我們通過這張圖來看一下,當目前的狀態為pending時。我們可以將pending狀態改變為fulfilled或者rejected中的一種。然而我們要記住,之前已經提到過Promise的狀態必須是三種之一。而且,如果一旦成功就不能失敗,一旦失敗就不能成功。

接下來我們依據上面狀態的描述來繼續、、、

clipboard.png

這裡當我們呼叫resolve和reject的時候我們需要做出狀態判斷,只有是pending狀態的時候才可以改變狀態為其他兩種的任意一種,如果不是:例如

clipboard.png

我們處理完了resolve和reject內建的邏輯,這裡有一個問題。在開發中,當Promise的執行遇到錯誤時,會直接變成rejected狀態,大家應該都知道,也就是下面的處理。

clipboard.png

我們在Promise的執行過程中如果捕獲到異常,就可以直接呼叫reject來結束Promise。

接下來我們看then方法。

clipboard.png

這樣我們就實現了一個簡單的Promise(才沒有。。。這才哪到哪),我們來試下效果吧。

clipboard.png

別忘了匯出我們的Promise。。

clipboard.png

clipboard.png

clipboard.png

我們看到下面的輸出結果,哇!!好激動有沒有(才沒有激動),我也實現了一個Promise!

但是!有一個問題,我們是不是弄丟了一個狀態???

what??哪個??仔細想一下好像是‘pending’丟掉了。。

so?那咋辦。

有人可能會說了,不是出了成功就是失敗嗎,為什麼會有等待狀態呢,我們來思考一下下面的程式碼。

clipboard.png

話說Promise應該都是支援非同步的吧?就像上面的程式碼,非同步執行resolve的時候我們是不是已經吧值給弄丟了?

並且我們想一下,弄丟這個值得一段時間是不是就是等待態也就是‘pending’的時候。。

所以,我們要怎麼處理這個pending呢?

我們想一下,在executor中的resolve和reject是不是都會吧我們傳入的值,傳到then方法的onfulfilled和onrejected中?另外,我們在then方法中做了對目前Promise的狀態的判斷。

所以我們在then方法中去處理‘pending’狀態。

怎麼去處理呢?我們可以在Promise中掛載兩個陣列。

clipboard.png

為什麼?這兩個陣列的作用是為了記錄pending狀態下的onfulfilled和onreject函式。我們來看then中的程式碼。

clipboard.png

我們可以看到在pending狀態下,這兩個陣列分別記錄了各自對應的then的回撥函式,並且儲存起來。

我們來捋一捋思路。

clipboard.png

所以說我們的陣列裡存的是一個一個的then的回撥函式,也就是一個一個function。

所以我們要在resolve和reject方法觸發的時候,去便利我們的陣列並且執行其中的方法,並且呢還要把我們成功的原因(self.value)和失敗的原因(self.reason)放到我們的回撥方法中去。說了這麼多有點繞。。上程式碼

clipboard.png

這樣就解決了非同步的問題。我們再來測試一下。

程式碼剛開始執行。

clipboard.png

2秒後。。。

clipboard.png

這時我們就拿到了非同步的值,是不是很開心!(有點,嘿嘿)

再看一下我們寫的全部的程式碼:

clipboard.png

到這裡我們簡單瞭解了Promise的一小部分原理,並且實現了一個非常簡單的Promise。今天就先寫到這裡,在下一章中我們會繼續瞭解Promise中的then方法是如何鏈式呼叫的,以及鏈式呼叫中的許多坑。。。

好啦,謝謝大家看到這裡。感謝。

clipboard.png

再次感謝。

相關文章