意象說明
Promise < 承諾
鑽牛角尖時間:Promise: resolver vs handler
不曉得讀者有沒有同樣的困擾:Promise
的 resolver 與 handler 有著不同的 signature (形式) 及啟動方式,看起來非常地不協調:
1 | // resolver 由 Promise() constructor 啟動 |
這樣的設計,著眼點是:對於已經使用 promise 模式的函數,早就已經回傳 Promise
物件了,使用上不涉及到 Promise
物件的建立,只要直接取用其回傳的 Promise
物件,呼叫其 #then()
函數即可,像這樣:
1 | $.get(url) |
至於那些需要自行處理 Promise
物件的函數,是尚未使用 promise 模式的函數。這些函數,若要使用 promise 模式[註1],必須先設法建立一個 Promise
物件,然後 Promise
物件在稍後呼叫指定的 resolver 函數,而 resolver 函數異步處理完畢後,再透過 resolve()
與 reject()
函數來完成整個處理過程。既然建立 Promise
物件和呼叫 resolver 函數這兩個動作似乎具有時間上的耦合,因此,這個責任就被設計,並落在 Promise
物件的 constructor 上:
1 | return new Promise(resolver); |
但是,真的不能處理得更好,更一致嗎?
嘗試 1:讓 resolver 的 signature 與 handler 一致
首先,必須先建立一個 Promise
物件。由於 Promise
提供有 Promise.resolve()
函數,可以建立一個已經 fulfilled 的 Promise
物件,顯然可以利用它來幫忙建立初始的 Promise
物件。有了初始的 Promise
物件,就可以對它呼叫 #then()
函數,然後以一致的 signature 撰寫 resolver 與 handler 了。
然而,因為要讓 resolver 與 handler 使用一致的 signature,這麼一來,resolver 就無法取得 resolve()
與 reject()
函數,所以 resolver 反而必須自行建立 Promise
物件:
1 | Promise.resolve(true) |
嗯...不好。看起來只是把該做的事情,搬到不同的地方做而已,並沒有讓事情更簡化。
嘗試 2:讓 handler 與 resolver 採用一般化的,一致的 signature
如果採用兩者的聯集形式: function (value, resolve, reject)
呢?
為此,我為 Promise
添加了兩個函數,分別是 Promise.first()
與 Promise#next()
,負責幫忙建立 Promise
物件,並且轉送 #then()
函數傳遞的值:
1 | Promise.first = function (handler) { |
看起來還蠻順眼的,讀者以為呢?
參考文章:
- Promise
- You're Missing the Point of Promises
- 有許多 Promise 程式庫,譬如 bluebird,提供 方法 幫助將 callback 形式的函數轉化為 Promise 形式。