Promise實現
這裡超級安利大家去看《深入淺出nodejs》4.3.2 章節,別問我為啥老是安利這個,問就真的好看啊!!
Promise 規範
promise的規範有一大堆,但是es6採用了Promise A+ 規範
相關文件Promise A+規範的友情解釋連結 規範說明英文版
相信大家看完上面給的那個連線已經對整個promise的執行過程都有個瞭解了。 這裡總結下
- 具有then方法,then()方法繼續返回Promise物件,以實現鏈式呼叫。
- Promise操作只會處在3種狀態的一種:未完成態(Pending)、完成態(Fulfilled)和失敗態(Rejected)。
- Promise的狀態只會出現從未完成態向完成態或失敗態轉化,不能逆反。完成態和失敗態不能互相轉化。
- Promise的狀態一旦轉化,將不能被更改。
- 接受完成態、錯誤態的回撥方法。在操作完成或出現錯誤時,將會呼叫對應方法
實現
以下為菜狗子根據規範約定實(chao)現(xi),有錯歡迎指出。
大佬們封裝的promise實現測試工具 ,有實現完成的,可以用這個測試下是否符合標準。
大佬們封裝好的例子想要看更多的,可以看這裡。菜狗子的實現參考其中belofte.js 為方便理解(就是懶)砍掉了許多型別判斷。
const PENDING = "Pending"; const FULFILLED = "Fulfilled"; const REJECTED = "Rejected"; const root = typeof window === "undefined" ? global : window; const isFunction = data => typeof data === "function"; const isMyPromise = fn => fn instanceof MyPromise; const isObject = data => data && (typeof data === "object" || typeof data === "function"); // 因為promise是微任務,我們儘可能的去模擬 const nextTick = (function() { if (typeof root.process === "object" && isFunction(root.process.nextTick)) { // node環境 return function(fn) { // process.nextTick 是微任務 root.process.nextTick(fn); }; } else { // 瀏覽器環境 return function(fn) { // setTimeout 是巨集任務 root.setTimeout(fn, 0); }; } })(); // 將promise由中間態到終態 const promiseResolutionProcedure = function(promise, result, async = true) { if (promise === result) { /** * 因為promise 如果收到的value是一個promise會等待他的結果。 * 所以如果接受到的value是本身就遞迴了。 * * @see https://promisesaplus.com/ 2.3.1 條規定 */ promise._reject(new TypeError("Chaining cycle detected for promise")); return; } // 如果接收到的是個promise if (isMyPromise(result)) { switch (result._state) { case FULFILLED: { nextTick(function() { promise._resolve(result._value); }); break; } case REJECTED: { nextTick(function() { promise._reject(result._reason); }); break; } case PENDING: { const _resolve = result._resolve; const _reject = result._reject; result._resolve = function(value) { _resolve.call(result, value); promise._resolve(value); }.bind(result); result._reject = function(reason) { _reject.call(result, reason); promise._reject(reason); }.bind(result); break; } } return; } // 如果接受到的是個thenable 物件 if (isObject(result) && isFunction(result.then)) { /** * 多次呼叫只有第一次有效 * * @see https://promisesaplus.com/ 2.3.3.3.3 條規定 */ let flag = false; const _resolve = function(value) { if (flag) { return; } flag = true; promiseResolutionProcedure(promise, value); }; const _reject = function(reason) { if (flag) { return; } flag = true; promise._reject(reason); }; const thenTemp = function() { try { result.then(_resolve, _reject); } catch (error) { _reject(error); } }; if (async) { nextTick(thenTemp); } else { thenTemp(); } return; } promise._resolve(result); return; }; class MyPromise { constructor(resolver) { if (!isFunction(resolver)) { throw new TypeError("Promise resolver undefined is not a function"); } /** @type { PENDING | FULFILLED | REJECTED} */ this._state = PENDING; this._value = undefined; this._reason = undefined; this._isPromise = true; /** * 因為同一個promise可以被then 多次。 * 這裡的多次不是指鏈式呼叫!!!! * 這裡理解了好久TAT */ this._resolveFnQueues = []; this._rejectFnQueuse = []; promiseResolutionProcedure(this, { then: resolver }, false); } _resolve(value) { if (this._state !== PENDING) { return; } this._state = FULFILLED; this._value = value; if (this._resolveFnQueues.length) { nextTick(() => { this._resolveFnQueues.forEach(cb => cb(value)); this._resolveFnQueues.length = 0; this._rejectFnQueuse.length = 0; }); } } _reject(reason) { if (this._state !== PENDING) { return; } this._state = FULFILLED; this._reason = reason; if (this._rejectFnQueuse.length) { nextTick(() => { this._rejectFnQueuse.forEach(cb => cb(reason)); this._resolveFnQueues.length = 0; this._rejectFnQueuse.length = 0; }); } } // then註冊一個監聽,在這個promise onFulfilled 或者 onRejected then(onFulfilled, onRejected) { onFulfilled = isFunction(onFulfilled) ? onFulfilled : MyPromise.resolve; onRejected = isFunction(onRejected) ? onRejected : MyPromise.reject; const chainPromise = new MyPromise(function() {}); const nextOnFulfilled = function(value) { let result; try { result = onFulfilled(value); promiseResolutionProcedure(chainPromise, result); } catch (error) { chainPromise._reject(error); } }; const nextOnRejected = function(reason) { let result; try { result = onRejected(reason); promiseResolutionProcedure(chainPromise, result); } catch (error) { chainPromise._reject(error); } }; switch (this._state) { case FULFILLED: { nextTick(() => { nextOnFulfilled(this._value); }); break; } case REJECTED: { nextTick(() => { nextOnRejected(this._reason); }); break; } case PENDING: { this._resolveFnQueues.push(nextOnFulfilled); this._rejectFnQueuse.push(nextOnRejected); } } return chainPromise; } catch(onRejected) { return this.then(undefined, onRejected); } toString() { switch (this._state) { case PENDING: return "Promise { <pending> }"; case FULFILLED: return "Promise { " + this._value + " }"; case REJECTED: return "Promise { <rejected> " + this._reason + " }"; } } static resolve(value) { return new MyPromise(resolve => resolve(value)); } static reject() { return new MyPromise((resolve, reject) => reject(value)); } } 複製程式碼
補充
async 實現
async 本質就是將 Generator 函式和自動執行器,包裝在一個函式裡
阮一峰大大的文章講的炒雞清楚了。這裡的內容也來自於那篇文章,本人也就溫習實現一下.
// async 的寫法 async function fn(args){ // ... } // 等同於 function fn(args){ return spawn(function*() { // ... }); } //spawn 的實現方式 function spawn(genF) { return new Promise(function(resolve, reject) { var gen = genF(); step(function() { return gen.next(undefined); }); function step(nextF) { try { var next = nextF(); } catch(e) { return reject(e); } if(next.done) { return resolve(next.value); } Promise.resolve(next.value).then(function(v) { step(function() { return gen.next(v); }); }, function(e) { step(function() { return gen.throw(e); }); }); } }); } 複製程式碼