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

xjylyh發表於2018-03-26

Hello everybody。我又來啦,還記得我們上一張實現的內容嗎?

clipboard.png

上一張我們實現了一個簡單的Promise。我們實現了Promise內部的簡單流程和then方法,並且實現了Promise的非同步呼叫。但是我們也留下了一些問題。。。

由於今天的程式碼是基於上一次我們實現的內容,所以不甚瞭解的小夥伴們可以去看我上一篇文章。。

文章地址:一步一步實現一個符合PromiseA+規範的Promise庫(1)

問題一:then方法的鏈式呼叫

我們都知道,一個Promise是可以在其中再次返回Promise的(當然也可以返回一個普通的值)。而且呢,返回的Promise或者返回的普通值我們需要去拿到它的值並且回傳給我們下一次的then方法中。比如:

clipboard.png

當然我們也可以在then方法中返回一個Promise;

clipboard.png

所以問題就來了。

問題二:如果在then方法中返回Promise或者普通值的情況,我們需要怎麼處理。

so,開搞。

我們先來處理第一個問題,讓我們的then方法支援鏈式呼叫,並且能接受普通值。

我們先來修改then方法中的對於成功狀態(onfulfilled)的判斷,因為下面的跟他是相同的道理。

clipboard.png

這裡我們首先來看定義的Promise2。為什麼要定義這樣一個變數呢?

我們要知道,如果要實現Promise中then方法的鏈式呼叫。當第一個then執行完畢並且把返回值給我們之後,我們也要返回這個值。

我們不禁要問了?一個值怎麼怎麼會有then方法呢?所以我們要把這個值包裝成一個Promise物件給返回出去。

所以說,我們需要使每個狀態都返回一個Promise。。說的有點多。我們來測試一下。

clipboard.png

我們接著改下面兩個狀態。

clipboard.png

我們來捋一捋。通過測試。

clipboard.png

我們看到程式碼執行了2.496秒,我們的測試結果是正確的;

到這裡我們就解決了then方法鏈式呼叫並且在then方法中返回一個普通值到下一次then方法的成功狀態中。

clipboard.png
是不是感覺很爽

接下來我們解決第二個問題。我們是需要允許在then方法中返回Promise的。。所以,我們也要處理這種情況。

Let us try to do it

clipboard.png
展示一下我深厚的英語功底

其實很簡單,我們需要一個統一的處理函式來進行在then中返回Promise的處理。。

我們先新建一個方法叫做resolvePromise(Promise的決定)

clipboard.png

在規範中說道。

clipboard.png

什麼意思呢,就是說如果Promise2和x指向的是同一個物件,我們這裡就要把需要返回的Promise2置為reject並且要返回一個型別錯誤。看下面的程式碼

clipboard.png
額,就是這樣

然後我們描述一下細節。。

clipboard.png

clipboard.png

emmmmmmmm...

這TM有點細節。。

好了不逗了,我們在程式碼裡面分析的很清楚了。我們來捋一捋思路。

在then方法中是可以返回一個Promise的對吧,然後我們拿到了then方法的執行結果,也就是可能是一個Promise或者是一個普通值(也就是x)。然後我們對這個x進行判斷,我們首先要判斷這個x是不是一個Promise對吧。

如果不是我們可以直接返回x,如果是的話,我們應該知道,Promise都會有then方法。我們接下來就需要判斷這個then方法是不是一個function。如果不是我們就直接返回這個then的值,emmm...他應給就是一個普通值。

如果這個then方法是一個function我們就可以直接去執行他。我們在兩個回撥中進行操作,如果執行的是onfulfilled則我們進行了關鍵的一步,就是遞迴呼叫我們的resolvePromise方法去看我們的onfulfilled傳進來的引數是否還是一個Promise,,就這樣一直呼叫,,直到x或者x.then是一個普通的值為止,然後我們就可以返回這個值,也就是resolve我們最後的值。

當然我們這裡加了try{}catch(){}還是為了避免程式執行中的錯誤。

然後我們就可以把我們之前的狀態判斷中的resolve替換成我們的resolvePromise方法,例如:

clipboard.png

當然下面的pending狀態也是一樣的。

clipboard.png

到這裡我們的Promise已經實現的差不多了。但是還有一個問題。我們思考以下程式碼;

clipboard.png

上面程式碼用的是ES6的原生的Promise

what?我們可以看到,第一個then方法中並沒有任何東西,然而我們第二個then中卻拿到了promies中resolve的值。

我們都知道,then方法中有onfulfilled和onreject兩個回撥函式,所以我們要處理一下這兩個回撥函式。

clipboard.png

注意onrejected中的default函式返回是用了throw。因為我們要返回到下一次的reject中 我們可以在then方法中處理一下這兩個回撥。判斷一下他們的型別,如果型別是function就代表這兩個回撥是有東西的。不然呢我們就返回一個預設的匿名函式,這個函式的引數就是上一次Promise返回的值,也就是當我們再次執行onfulfilled或者onrejected的時候就可以直接拿到這個值了。也就完成了我們想要的效果。

現在,我們基本上就實現了一個比較完整地Promise。我們實現了Promise非同步呼叫,在then方法中返回Promise或者值,實現了then方法中可以沒有回撥函式也能把執行結果傳入下一次的then方法中。

當然我們基本清楚了Promise的基本原理,以後我們就可以說我們既會使用又可以實現一個Promise。

clipboard.png

當然還有一些小小的問題,就是Promise中有許多方法我們沒有實現。例如:

Promise.resolve() . Promise.reject() ..還有.catch()方法 Promise.all()方法等等

在下一篇文章中,我們會一一的去實現這些方法,並且會介紹一下前端開發這些年的非同步發展流程

最初的callback->Promise->generator函式->我們現在常用的 async await

好了,就到這裡吧。看到這裡蠻不容易,謝謝大家。

clipboard.png

相關文章