手寫Promise原始碼及方法
阿新 • • 發佈:2020-09-17
原文: 本人掘金文章
關注公眾號: 微信搜尋 web全棧進階
; 收貨更多的乾貨
一、Es5語法
function MyPromise (executor) { this.state = 'pending' // 成功的值 this.data = undefined // 失敗的原因 this.reason = undefined this.callbacks = [] // 成功回撥, state 重置為 resolved let resolve = (value) => { if (this.state !== 'pending') return this.state = 'resolved' this.data = value // 立即執行非同步回撥函式 setTimeout(_ => { this.callbacks.forEach(callback => { callback.onResolved(value) }) }) } // 失敗回撥, state 重置為 rejected let reject = (reason) => { if (this.state !== 'pending') return this.state = 'rejected' this.reason = reason setTimeout(_ => { this.callbacks.forEach(callback => { callback.onRejected(reason) }) }) } // 如果executor執行報錯,直接執行reject try{ executor(resolve, reject) } catch (err) { reject(err) } } // Promise原型鏈上的then方法,可以接收兩個引數(且是回撥函式),成功/失敗,並且每次返回的都是一個新的Promise MyPromise.prototype.then = function (onResolved, onRejected) { let _this = this onResolved = typeof onResolved === 'function' ? onResolved : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => console.error(reason) // promise物件當前狀態為pending // 此時並不能確定呼叫onResolved還是onRejected,需要等待promise的狀態改變 return new MyPromise((resolve, reject) => { /* * 1、返回的Promise的結果是由onResolved/onrejected決定的 * 2、返回的是Promise物件 (根據執結果決定Promise的返回結果) * 3、返回的不是Promise物件 (該值就是Promise的返回結果) * 4、丟擲異常 異常的值為返回的結果 */ // 統一處理函式 function handle (callback) { try { const result = callback(_this.data) if (reject instanceof MyPromise) { result.then(value => { resolve(value) }, reason => { reject(reason) }) } else { resolve(result) } } catch (e) { reject(e) } } if (_this.state === 'resolved') { setTimeout(_ => { handle(onResolved) }) } if (_this.state === 'rejected') { setTimeout(_ => { handle(onRejected) }) } if (_this.state === 'pending') { _this.callbacks.push({ onResolved() { handle(onResolved) }, onRejected() { handle(onResolved) } }) } }) } // 錯誤捕獲 MyPromise.prototype.catch = function (onRejected) { return this.then(null, onRejected) } MyPromise.resolve = function (value) { if (value instanceof MyPromise) return value return new MyPromise(resolve => resolve(value)) } MyPromise.reject = function (reason) { console.log(reason) return new MyPromise((resolve, reject) => reject(reason)) // 返回一個reject狀態Promise物件 } /* * Promise.all可以將多個Promise例項包裝成一個新的Promise例項。 * 同時,成功和失敗的返回值是不同的,成功的時候返回的是一個結果陣列,而失敗的時候則返回最先被reject失敗狀態的值 */ MyPromise.all = function (promises) { if (typeof promises !== 'object' || promises.constructor !== Array) return console.error('引數需為陣列!') let count = 0 let values = new Array(promises.length) return new MyPromise((resolve,reject) => { promises.forEach((promise, index) => { MyPromise.resolve(promise).then(value => { count++ values[index] = value if (count === promises.length) resolve(values) }, error => { reject(error) }) }) }) } /* * Promise.race 返回陣列例項中最先改變狀態的例項(無論成功還是失敗) * */ MyPromise.race = function (promises) { return new MyPromise((resolve,reject) => { promises.forEach(promise => { MyPromise.resolve(promise).then(value => { resolve(value) }, error => { reject(error) }) }) }) }
二、Es6 class 語法
class _Promise { constructor (executor) { const _this = this this.state = 'pending' // 成功的值 this.data = undefined // 失敗的原因 this.reason = undefined this.callbacks = [] function resolve (value) { if (_this.state === 'pending') return _this.state = 'resolved' _this.data = value setTimeout(_ => { _this.callbacks.forEach(callback => { callback.onResolved(value) }) }) } function reject (reason) { if (_this.state === 'pending') return _this.state = 'rejected' _this.reason = reason setTimeout(_ => { _this.callbacks.forEach(callback => { callback.onRejected(reason) }) }) } executor(resolve, reject) } then(onResolved, onRejected) { const _this = this onResolved = typeof onResolved === 'function' ? onResolved : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => console.error(reason) return new _Promise((resolve, reject) => { function handle (callback) { try { const result = callback(_this.data) if (reject instanceof _Promise) { result.then(value => { resolve(value) }, reason => { reject(reason) }) } else { resolve(result) } } catch (e) { reject(e) } } if (_this.state === 'resolved') { setTimeout(_ => { handle(onResolved) }) } if (_this.state === 'rejected') { setTimeout(_ => { handle(onRejected) }) } if (_this.state === 'pending') { _this.callbacks.push({ onResolved() { handle(onResolved) }, onRejected() { handle(onResolved) } }) } }) } catch (onRejected) { return this.then(null, onRejected); } static resolve(value) { if (value instanceof _Promise) return value; return new _Promise(resolve => resolve(value)) // 返回一個resolved狀態的新Promise物件 } static reject(reason) { return new _Promise((resolve, reject) => reject(reason)); // 返回一個reject狀態新Promise物件 } static all(promises) { let count = 0 let values = new Array(promises.length) return new _Promise((resolve, reject) => { promises.forEach((promise, index) => { _Promise.resolve(promise).then(value => { count++ values[index] = value if (count === promises.length) resolve(values) }, reason => reject(reason)) }) }) } static race(promises) { return new _Promise((resolve, reject) => { promises.forEach(promise => { _Promise.resolve(promise).then(value => resolve(value)) }, reason => reject(reason)) }) } }
三、測試
/* 測試 */ window.onload = function () { f3() let p1 = new MyPromise((resolve,reject) => { resolve('p1 執行完畢') }) let p2 = new MyPromise((resolve,reject) => { resolve('p2執行完畢') }) let p3 = MyPromise.reject('失敗') MyPromise.all([p1, p2]).then(res => { console.log(res) }).catch(error => { console.log(error) }) MyPromise.race([p1, p2, p3]).then(res => { console.log(res) }).catch(error => { console.log(error) }) } function f1 () { return new _Promise((resolve,reject) => { f4() resolve(1) }) } function f2 () { console.log('f2f2f2f2f2f2f2f2') } function f4 () { console.log('f4f4f4f4f4f4f4f4') } function f3 () { let p = f1() p.then(res => { console.log(res) }).catch(err => { console.log(err) }) f2() } // 測試結果 // f4f4f4f4f4f4f4f4 // f2f2f2f2f2f2f2f2 // 失敗 // ["p1 執行完畢", "p2執行完畢"] // p1 執行完畢