不能免俗地貼個Promise標準連接Promises/A+。ES6的Promise有不少方法,包括Promise.all()/Promise.resolve()/Promise.reject()等,但其實這些都是Promises/A+規範以外的,Promises/A+規範只定義了一個Promise.then()方法,這是Promise的核心。git
new Promise((resolve, reject) => { let a = 0; if (a > 1) { resolve(a); } else { reject(a); } }).then(res => { console.log(res); }, err => { console.log(err); })
Promise接收一個函數做爲參數,咱們稱之爲executor,該函數有兩個參數resolve和reject,這兩個參數也都是函數,而且,它們定義在Promise內部。github
那麼咱們定義一個class並定義一個_isFunction方法,用來校驗構造函數的參數必須是函數。再定義resolve和reject這兩個方法。編程
class MyPromise{ constructor(executor){ if(!this._isFunction(executor)){ throw new Error(`Promise resolver ${executor} is not a function`); } } _isFunction(val){ return Object.prototype.toString.call(val) === '[object Function]'; } _resolve(){ } _reject(){ } }
Promise有三種狀態,分別是pending(等待中)、fulfilled(成功)、rejected(失敗)。狀態改變只能從pending => fulfilled,或者pending => rejected。數組
resolve的做用,就是將Promise的狀態從pending改成fulfilled,它接收一個參數做爲Promise執行成功的值,這個值會傳給then的第一個回調函數。reject的做用是將Promise的狀態從pending改成rejected,它也接收一個參數做爲Promise執行失敗的值,這個值會傳給then的第二個回調函數。promise
那麼咱們定義好狀態_status、_resolve、_reject,再定義兩個數組_handleFulfilled、_handleRejected,分別存放then的成功和失敗回調集合。當用戶調用resolve或reject方法後,開始異步調用_handleFulfilled或_handleRejected數組中的回調。異步
class MyPromise { constructor(executor) { if (!this._isFunction(executor)) { throw new Error(`${executor} is not a function`); } this._status = "pending"; this._value = undefined; this._handleFulfilled = []; this._handleRejected = []; // 不少文章在這裏給executor加了try catch,實際上原生Promise的executor中的錯誤並無捕獲 executor(this._resolve.bind(this), this._reject.bind(this)); } _isFunction(val) { return Object.prototype.toString.call(val) === "[object Function]"; } _resolve(value) { if(this._status === 'pending'){ this._status = "fulfilled"; this._value = value; let cb; // 異步按順序調用並清空回調 setTimeout(() => { while(cb = this._handleFulfilled.shift()){ cb(value); } }, 0) } } _reject(value) { if(this._status === 'pending'){ this._status = "rejected"; this._value = value; let cb; // 異步按順序調用並清空回調 setTimeout(() => { while ((cb = this._handleRejected.shift())) { cb(value); } }, 0); } } }
Promise.then定義了兩個回調onFulfilled和onRejected異步編程
promise.then(onFulfilled, onRejected)
它們分別在Promise執行成功/失敗時執行,它們都是可選的,Promises/A+規範規定,若是onFulfilled或onRejected不是函數,將被忽略,Promise會繼續執行下一個then的回調。好比下面的例子會輸出1,.then(2)則被忽略了。函數
new Promise((resolve, reject) => { resolve(1); }) .then(2) .then((res) => { console.log(res); });
then能夠鏈式調用,是由於每一個then都會返回一個新的Promise。then執行onFulfilled仍是onRejected,取決於Promise的狀態,若是Promise狀態爲pending,只會將onFulfilled和onRejected分別push到_handleFulfilled和_handleRejected數組;若是狀態爲fulfilled,會執行對應的onFulfilled;若是狀態是rejected,執行對應的onRejected;測試
那麼then方法的基本結構以下this
then(onFulfilled, onRejected) { const self = this; const { _value, _status } = this; // 若是onFulfilled、onRejected不是函數,強制改成函數,而且該函數直接返回接收到的參數,傳後面的then的回調函數 onFulfilled = self._isFunction(onFulfilled) ? onFulfilled : (v) => v; onRejected = self._isFunction(onRejected) ? onRejected : (v) => v; return new MyPromise((resolve, reject) => { switch (_status) { case "pending": self._handleFulfilled.push(onFulfilled); self._handleRejected.push(onRejected); break; case "fulfilled": onFulfilled(_value); // todo break; case "rejected": onRejected(_value); // todo break; default: throw new Error('Promise resolver Unverified status'); break; } }); }
在then鏈式調用的狀況下,若是前一個then返回的是一個新Promise,後一個then的回調必須等這個新Promise的狀態改變後纔會執行。舉例,下面的代碼輸出1以後,等待3秒纔會輸出2:
new Promise(resolve => { resolve() }).then(() => { return new Promise(resolve => { console.log(1); setTimeout(() => { resolve() }, 3000) }) }).then(() => { console.log(2); })
所以要對then的回調函數的返回值作個判斷,若是返回值不是Promise,利用resolve直接返回這個值;若是返回值是Promise,就要等這個Promise狀態變化以後再返回,而Promise狀態變化以後必定會調用then的回調函數,利用這個特性,將resolve、reject做爲then的回調函數便可。
then(onFulfilled, onRejected) { const self = this; const { _value, _status } = this; // 若是onFulfilled、onRejected不是函數,強制改成函數,而且該函數直接返回接收到的參數,傳後面的then的回調函數 onFulfilled = self._isFunction(onFulfilled) ? onFulfilled : (v) => v; onRejected = self._isFunction(onRejected) ? onRejected : (v) => v; return new MyPromise((resolve, reject) => { const fulfilled = (value) => { const res = onFulfilled(value); if (res instanceof MyPromise) { res.then(resolve, reject); } else { resolve(res); } }; const rejected = (value) => { const res = onRejected(value); if (res instanceof MyPromise) { // 這裏是重點 res.then(resolve, reject); } else { reject(res); } }; switch (_status) { case "pending": self._handleFulfilled.push(fulfilled); self._handleRejected.push(rejected); break; case "fulfilled": fulfilled(_value); break; case "rejected": rejected(_value); break; default: throw new Error('Promise resolver Unverified status'); break; } }); }
完整代碼
class MyPromise { constructor(executor) { if (!this._isFunction(executor)) { throw new Error(`${executor} is not a function`); } this._status = "pending"; this._value = undefined; this._handleFulfilled = []; this._handleRejected = []; // 不少文章在這裏給executor加了try catch,實際上原生Promise的executor中的錯誤並無捕獲 executor(this._resolve.bind(this), this._reject.bind(this)); } _isFunction(val) { return Object.prototype.toString.call(val) === "[object Function]"; } _resolve(value) { if (this._status === "pending") { this._status = "fulfilled"; this._value = value; let cb; // 異步按順序調用並清空回調 setTimeout(() => { while ((cb = this._handleFulfilled.shift())) { cb(value); } }, 0); } } _reject(value) { if (this._status === "pending") { this._status = "rejected"; this._value = value; let cb; // 異步按順序調用並清空回調 setTimeout(() => { while ((cb = this._handleRejected.shift())) { cb(value); } }, 0); } } then(onFulfilled, onRejected) { const self = this; const { _value, _status } = this; // 若是onFulfilled、onRejected不是函數,強制改成函數,而且該函數直接返回接收到的參數,傳後面的then的回調函數 onFulfilled = self._isFunction(onFulfilled) ? onFulfilled : (v) => v; onRejected = self._isFunction(onRejected) ? onRejected : (v) => v; return new MyPromise((resolve, reject) => { const fulfilled = (value) => { const res = onFulfilled(value); if (res instanceof MyPromise) { res.then(resolve, reject); } else { resolve(res); } }; const rejected = (value) => { const res = onRejected(value); if (res instanceof MyPromise) { // 這裏是重點 res.then(resolve, reject); } else { reject(res); } }; switch (_status) { case "pending": self._handleFulfilled.push(fulfilled); self._handleRejected.push(rejected); break; case "fulfilled": fulfilled(_value); break; case "rejected": rejected(_value); break; default: throw new Error('Promise resolver Unverified status'); break; } }); } }
測試一下,先輸出1,3秒後輸出2,說明MyPromise的基本功能沒問題了。
new MyPromise((resolve) => { console.log(1); setTimeout(() => { resolve(2); }, 3000) }).then(res => { console.log(res); })
最後,總結一下,Promise是如何實現異步編程的?
Promise接收一個函數爲參數,傳入了兩個內部的方法resolve和reject,而後用then註冊回調函數,手動調用resolve或reject就能夠依次執行then的回調,而且給回調函數傳值。若是then返回的也是Promise,一樣的,手動調用resolve或reject後,纔會繼續往下執行。
其實本質上仍是回調函數,只不過寫法變了。
本文GitHub連接:Promise是如何實現異步編程的?