Promise 鏈式調用原理精簡示例
前言
在面試的過程中,總有一些面試官會問你,手寫一個簡易版的Promise
得行不,得行的話就寫一個出來看看,啪一哈,就把紙和筆給瞭你。 我們思索半天就寫出來瞭個下面這個。 哦豁,高薪張開瞭它的翅膀,遠離瞭我們。
class Promise { constructor (resolve, reject) {} resolve () {} reject (){} then () {} catch () {} once () {} all () {} ... }
本篇文章將不講述手寫出來一個簡易的Promise
,感興趣的朋友可以去看我這篇文章 -> Promise詳解-手寫Promise,實現一款自己的簡易Promise
本篇文章記錄的是如何實現Promise
的核心功能之一的.then 鏈式調用,采用構造函數的寫法,本篇文章的代碼不考慮任何容錯和異常處理,隻單獨說明其鏈式調用原理,方便理解。
先擺上完整代碼,去掉註釋和一些換行共20行有餘。
代碼
function CustomPromise (fn) { // 回調收集 this.callbackList = [] // 傳遞給Promise處理函數的resolve const resolve = (value) => { // 註意promise的then函數需要異步執行 setTimeout(() => { // 這裡直接往實例上掛個data this.data = value; // 把callbackList數組裡的函數依次執行一遍 this.callbackList.forEach(cb => cb(value)) }); } /* 執行用戶傳入的函數 並且把resolve方法交給用戶執行 */ fn(resolve) } /* 重點 */ // 往構造函數的原型上掛載.then方法 CustomPromise.prototype.then = function (onReaolved) { // return 一個promise 實例 return new CustomPromise((resolve) => { // 往回調數組中插入回調 this.callbackList.push(()=>{ const response = onReaolved(this.data) // 判斷是否是一個 CustomPromise if(response instanceof CustomPromise){ // resolve 的權力被交給瞭user promise response.then(resolve) }else{ // 如果是普通值,直接resolve // 依次執行callbackList裡的函數 並且把值傳遞給callbackList resolve(response) } }) }) }
經典案例
new CustomPromise((resolve) => { setTimeout(() => { // resolve1 resolve(1); }, 300); }).then((res) => {// then1 console.log(res); // 返回一個 CustomPromise return new CustomPromise((resolve) => { setTimeout(() => { // resolve2 resolve(2); }, 300); }); }).then(res => {// then2 console.log(res); });
完整的代碼和例子已奉上,現在來進行解釋。 固然結果很重要,但過程也很重要。我們要做到 知其然知其所以然。
解析
第一步
首先,我們我們先創建這樣一個Promise
, 這裡需要使用匿名函數,不能使用箭頭函數,或者你可以根據這個方法已class
類的方法進行實現。
大概步驟如下:
- 聲明構造函數/類
- 在內部聲明一個數組名為
callbackList
用來裝回調,並放到this
裡面 - 聲明一個名
resolve
的方法,用來傳遞給Promise
進行處理,註意:resolve 內部需要為異步,這裡可以采用 setTimeout 實現 - 循環
callbackList
並執行裡面的方法
寫出來後的樣子長這樣:
function CustomPromise (fn) { // 回調收集 this.callbackList = [] // 傳遞給Promise處理函數的resolve const resolve = (value) => { // 註意promise的then函數需要異步執行 setTimeout(() => { // 這裡直接往實例上掛個data this.data = value; // 把callbackList數組裡的函數依次執行一遍 this.callbackList.forEach(cb => cb(value)) }); } /* - fn 為用戶傳進來的函數 - 執行用戶傳入的函數 - 並且把resolve方法交給用戶執行 */ fn(resolve) }
第二步
註意:第二步是本篇文章的重點,也是這個核心功能的一個重點。
我們需要往CustomPromise
的原型上掛載一個.then
的方法。並返回的是一個Promise
實例,這裡依舊使用的是匿名函數。
完整代碼長這樣:
// 往構造函數的原型上掛載.then方法 CustomPromise.prototype.then = function (onReaolved) { // return 一個promise 實例 return new CustomPromise((resolve) => { // 往回調數組中插入回調 this.callbackList.push(()=>{ const response = onReaolved(this.data) // 判斷是否是一個 CustomPromise if(response instanceof CustomPromise){ // resolve 的權力被交給瞭user promise response.then(resolve) }else{ // 如果是普通值,直接resolve // 依次執行callbackList裡的函數 並且把值傳遞給callbackList resolve(response) } }) }) }
寫出來過後,在結合上面的那個例子使用,不能說和原生Promise
一模一樣,但使用起來的鏈式效果卻是一毛一樣。
分析說明,此過程需結合上文中的案例一起閱讀
const promise1 = new CustomPromise((resolve) => { setTimeout(() => resolve(1)); }) promise1.then((res) => { const userPromise = new CustomPromise((resolve) => { setTimeout(() => resolve(2), 300); }); return userPromise });
說明:
- 我們把
new Promise
返回的實例叫做promise1
- 在
Promise.prototype.then
的實現中,我們構造瞭一個新的promise
返回,叫它promise2
在調用then
方法的時候,用戶手動構造瞭一個promise
並且返回,用來做異步的操作,叫它userPromise
,那麼在then
的實現中,內部的this
其實就指向promise1
而promise2
的傳入的fn
函數執行瞭一個this.cbs.push()
的操作,其實是往promise1
的callbackList
數組中push
瞭一個函數,等待後續執行
CustomPromise.prototype.then = function (onReaolved) { // promise 2 return new CustomPromise((resolve) => { // 往回調數組中插入回調 this.callbackList.push(()=>{}) }) }
如果用戶傳入給then
的onResolved
方法返回的是個userPromise
,那麼這個userPromise
裡用戶會自己去在合適的時機 resolvePromise2
,那麼進而這裡的response.then(resolve)
中的resolve
就會被執行
if(response instanceof CustomPromise){ response.then(resolve) }
再結合上面的經典案例看,我這裡再放一遍
new CustomPromise((resolve) => { setTimeout(() => { // resolve1 resolve(1); }, 300); }).then((res) => {// then1 console.log(res); // userPromise return new CustomPromise((resolve) => { setTimeout(() => { // resolve2 resolve(2); }, 300); }); }).then(res => {// then2 console.log(res); });
then1
這一整塊其實返回的是promise2
,那麼then2
其實本質上是promise2.then(()=>{})
, 也就是說then2
註冊的回調函數,其實進入瞭promise2
的callbackList
回調數組裡。 又因為我們剛剛知道,resolve2
調用瞭之後,userPromise
會被resolve
,進而觸發promise2
被resolve
,進而 promise2
裡的callbackList
數組被依次觸發。 這樣就實現瞭用戶自己寫的resolve2
執行完畢後,then2
裡的邏輯才會繼續執行,也就是異步鏈式調用。
說句題外話,這個有點繞,當時還是看瞭好一會才看懂。
好瞭,當你看到這裡的時候,這篇文章已經接近尾聲瞭,是時候進行總結瞭。
總結
本篇文章隻是根據其原理實現的一個簡易鏈式調用的過程,真正的Promise
並沒有這麼簡單,和上文中的比起來復雜很多,而且涉及到很多的異常、容錯、邊界等情況的處理。
最後推薦一下Promise A+規范
-> 點我查看規范,很值得去看,相信看完後會對Promise
有一個更深的瞭解。
以上就是Promise 鏈式調用原理精簡示例的詳細內容,更多關於Promise 鏈式調用的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 淺析Promise的介紹及基本用法
- 徹底搞懂 javascript的Promise
- 前端JavaScript之Promise
- 字節飛書面試promise.all實現示例
- ES6的Promise用法詳解