最近看到好多講解Promise源碼解析,或者本身實現一個Promise的文章,忽然想本身造個輪子試一試。javascript
先說明一下,該輪子並不徹底遵照任何標準和規範,只是對標準Promise使用後的理解和感覺而編寫的,純屬興趣研究。java
下面是實現代碼:node
// 對象類型判斷 const is = (typeAsString) => obj => Object.prototype.toString.call(obj) === typeAsString // 判斷是否爲一個Error對象 const isError = is('[object Error]') /** * 自定義Promise對象 * @param {(resolve: (value: any) => void, reject: (reason: any) => void) => void} executor */ function MyPromise(executor) { this.executor = executor // 初始狀態爲pending... this.status = 'pending' /** * 內部斷定狀態,只有處於pending狀態纔可繼續執行 * @param {number} value */ function resolve(value) { if (this.status === 'pending') { // 確保只執行一次 this.onfulfilled = ___onfulfilled.call(this, value) } } /** * 爲了緩存resolve方法的執行結果 * @param {*} value value就是resolve方法的執行結果 */ function ___onfulfilled(value) { this.status = 'fulfilled' // 更改內部狀態 /** * @param {(value: number) => void} onfulfilled 這裏是then方法中傳入的參數 */ return (onfulfilled) => { return onfulfilled(value) // } } /** * 觸發異常的方法 * @param {string} reason */ function reject(reason) { if (this.status === 'pending') { // 確保只執行一次 this.onrejected = ___onrejected.call(this, reason) } } /** * * @param {Error} reason 若是傳入的不是一個Error對象,那麼會使用Error包裝一下 */ function ___onrejected(reason) { this.status = 'rejected' // 更改內部狀態 return (onrejected) => { reason = isError(reason) ? reason : new Error(reason) return onrejected(reason) } } /** * @param {(value: number) => any} onfulfilled 處理成功的函數 * @param {(reason: any) => void} onrejected 處理出現異常的函數,若是傳入該參數,那麼catch方法就捕獲不到了 */ this.then = function(onfulfilled, onrejected) { const self = this return new MyPromise((resolve, reject) => { setTimeout(function waitStatus() { switch (self.status){ case 'fulfilled': // resolved if (onfulfilled) { // 將onfulfilled方法的返回值交給resolve,確保下一個.then方法可以獲得上一個.then方法的返回值 const nextValue = self.onfulfilled(onfulfilled) resolve(nextValue) } else { resolve() // 沒有傳入參數,僞裝傳入了參數:) } break case 'rejected': // rejected if (!onrejected) { // 若是沒有傳遞onrejected參數,默認實現一個,確保catch方法可以捕獲到 onrejected = (reason) => reason } const nextReject = self.onrejected(onrejected) reject(nextReject) break case 'pending': // default: setTimeout(waitStatus, 0) // 只要是pending狀態,繼續等待,直到不是pending break } }, 0); }) } /** * 捕獲異常 * @param {(reason: any) => void} onrejected */ this.catch = function(onrejected) { const self = this setTimeout(function reject() { if (self.status === 'rejected') { self.onrejected(onrejected) } else { setTimeout(reject, 0); } }, 0); } // 直接執行 this.executor(resolve.bind(this), reject.bind(this)); }
目前不考慮參數傳入的正確性,假設傳入的參數所有是正確的狀況下,在nodejs環境下可以正常運行。如下是測試代碼:git
// 覆蓋nodejs環境中的標準Promise對象 global.Promise = MyPromise async function test () { const r = await new Promise((resolve) => { setTimeout(() => { resolve(121) }, 1000); }) console.log(r) // 打印121 } test()
以上代碼主要是使用setTimeout方法去檢查Promise對象內部的狀態,一旦發生變化當即做出相應的處理。github
由於是靠setTimeout方法檢查Promise內部的狀態,因此屬於宏指令任務,執行的優先級不像標準Promise那麼高。緩存
setTimeout(() => { console.log(1) }, 0); new MyPromise((resolve, reject) => { console.log(2) resolve(3) }).then(v => { console.log(v) })
上面代碼的輸出是2,1,3
標準Promise的輸出結果應該是2,3,1async
源代碼在此。謝謝觀看!函數