Promise是異步編程的一種解決方案,比傳統的解決方案(回調函數和事件)更合合理、強大。所謂Promise,簡單來講就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promies是一個對象,從它能夠獲取異步操做的消息。Promise提供統一的API,各類異步操做均可以用一樣的方法進行處理編程
promise有三種狀態,pending(進行中)、fulfilled/resolved(已成功)和rejected(已失敗)設計模式
Promise的實現過程,其主要使用了設計模式中的觀察者模式:數組
Promise 是經過.then方法來實現多個異步操做的順序執行
Promise的內部也有一個 defers 隊列存放事件,而 .then 方法的做用和發佈訂閱模式的on方法同樣是用來訂閱事件的,每次調用 .then 方法就會往defers隊列中放入一個事件,當異步操做完成時, resolve方法標示前一個異步過程完成並從defers隊列中取出第一個事件執行並返回當前對象保證鏈式調用,以此類推,就完成了全部異步過程的隊列執行promise
實例化Promise,返回Promise對象 const promise = new Promise(function(resolve, reject) { // ... some code if (/* 異步操做成功 */){ resolve(value); } else { reject(error); } }); promise.then(function(value){ // success }, function(err){ // failure })
Promise對象是一個構造函數,用來生成Promise實例。經過new返回一個Promise實例
Promise構造函數接受一個函數做爲參數,該函數接受resolve和reject兩個回調函數做爲參數,它們由 JavaScript 引擎提供,不用本身部署,用來改變Promise的狀態異步
then是Promise構造函數原型鏈上的方法,Promise.prototype.then,then方法分別指定resolved狀態和rejected狀態的回調函數異步編程
then方法能夠接受兩個回調函數做爲參數。第一個回調函數是Promise對象的狀態變爲resolved時調用,第二個回調函數是Promise對象的狀態變爲rejected時調用【可選】函數
第一步,初步構建。Promise 的參數是函數 executor,把內部定義 resolve 方法做爲參數傳到 executor 中,調用 executor。當異步操做成功後會調用 resolve 方法,而後就會執行 then 中註冊的回調函數;並經過then中的return this實現鏈式調用測試
function MyPromise(executor) { var value = null, callbacks = []; //callbacks爲數組,由於可能同時有不少個回調 this.then = function (onFulfilled) { callbacks.push(onFulfilled); return this // 返回Promise對象,實現鏈式調用 }; // 成功回調 function resolve(value) { setTimeout(function() { // Promises/A+規範明確要求回調須要經過異步方式執行,用以保證一致可靠的執行順序;經過setTimeout機制,將resolve中執行回調的邏輯放置到JS任務隊列末尾,以保證在resolve執行時,then方法的回調函數已經註冊完成 callbacks.forEach(function (callback) { callback(value); }); }, 0) } executor(resolve); }
第二步,添加狀態state
this
function MyPromise(executor) { var state = 'pending', value = null, callbacks = []; this.then = function (onFulfilled) { if (state === 'pending') { callbacks.push(onFulfilled); return this; } onFulfilled(value); return this; }; function resolve(newValue) { value = newValue; state = 'fulfilled'; setTimeout(function () { callbacks.forEach(function (callback) { callback(value); }); }, 0); } executor(resolve); }
完整實現代碼prototype
function MyPromise(executor) { this._status = 'PENDING' this._value = null this._reason = null this._resolveFns = [] this._rejectFns = [] var handler = function(state, value) { if (this.state !== 'PENDING') return let promise = this let fns = [] setTimeout(function() { promise.state = state let st = state === 'FULFILLED' fns = st ? promise['_resolveFns'] : promise['_resolveFns'] fns.forEach(fn => { value = fn.call(promise, value) || value }) promise[st ? '_value' : '_reason'] = value; promise['_resolveFns'] = promise['_resolveFns'] = undefined; }, 0) } var resolve = function(value) { handler.call(this, 'FULFILLED', value); } var reject = function(reason){ handler.call(this, 'REJECTED', reason); } executor(resolve,reject) } MyPromise.prototype.then = function(resolveFn, rejectFn) { var promise = this //串行 return new Promise(function(resolveNext, rejectNext) { // 在 then 方法,對then方法的回調函數返回結果 ret 進行判斷,若是是一個 promise 對象,就會調用其 then 方法,造成一個嵌套,直到其不是promise對象爲止 function resolveHandler(value) { var result = typeof resolveFn === 'function' && resolveFn(value) || value if (result && typeof result.then === 'function') { result.then(function(value) { resolveNext(value) }, function(reason) { rejectNext(reason) }) } else { resolveNext(result) } } function rejectHandler(reason) { var reason = typeof rejectFn === 'function' && rejectFn(reason) || reason rejectNext(reason) } if(promise._status === 'PENDING'){ promise._resolveFns.push(resolveHandler); promise._rejectFns.push(rejectHandler); }else if(promise._status === 'FULFILLED'){ // 狀態改變後的then操做,馬上執行 resolveHandler(promise._value); }else if(promise._status === 'REJECTED'){ rejectHandler(promise._reason); } }) }
測試
// 實際上,fn中的resolve、reject函數分別是then方法中對應的函數參數 var fn5 = function(resolve, reject){ console.log('oooo1') resolve('5'); console.log('ssss1') } var fn6 = function(resolve, reject){ resolve('6'); } new MyPromise(fn5).then(function(data){ console.log(data); return new MyPromise(fn6); }).then(function(data){ console.log(data); });
MyPromise.prototype.catch = function(reject) { return this.then(undefined, reject) } MyPromise.prototype.delay = function(time) { return this.then(function(ori){ return Promise.delay(ms, value || ori); }) } MyPromise.delay = function(ms, value) { return new MyPromise(function(resolve, reject){ setTimeout(function(){ resolve(value) }, ms) }) } MyPromise.resolve = function(value) { return new MyPromise(function(resolve, reject){ resolve(value) }) } MyPromise.reject = function(value) { return new MyPromise(function(resolve, reject){ reject(value) }) } MyPromise.all = function(promises) { return new MyPromise(function(resolve, reject) { var result = [] function resolver(index) { return function(val) { result.push(val) while(--index) { resolve(result) } } } function rejecter(reason) { reject(reason) } for (var i = 0; i < promises.length; i++) { promises[i].then(resolver(i), rejecter) } }) } MyPromise.race = function(promises) { return new MyPromise(resolve, reject) { function resolver(val) { resolve(val) } function rejecter(reason) { reject(reason) } for (var i = 0; i < promises.length; i++) { promises[i].then(resolver, rejecter) } } }
這個是將promise和一個值x做爲輸入的一個抽象操做。若是這個x是支持then的,他會嘗試讓promise接受x的狀態;不然,他會用x的值來fullfill這個promise。運行這樣一個東西,遵循如下的步驟 2.3.1 若是promise和x指向同一個對象,則reject這個promise使用TypeError。 2.3.2 若是x是一個promise,接受他的狀態 2.3.2.1 若是x在pending,promise必須等待x的狀態改變 2.3.2.2 若是x被fullfill,那麼fullfill這個promise使用同一個value 2.3.2.3 若是x被reject,那麼reject這個promise使用同一個理由 2.3.3 若是x是一個對象或者是個方法 2.3.3.1 then = x.then 2.3.3.2 若是x.then返回了錯誤,則reject這個promise使用錯誤。 2.3.3.3 若是then是一個function,使用x爲this,resolvePromise爲一參,rejectPromise爲二參, 2.3.3.3.1 若是resolvePromise被一個值y調用,那麼運行[[Resolve]](promise, y) 2.3.3.3.2 若是rejectPromise被reason r,使用r來reject這個promise 2.3.3.3.3 若是resolvePromise和rejectPromise都被調用了,那麼第一個被調用的有優先權,其餘的beihulue 2.3.3.3.4 若是調用then方法獲得了exception,若是上面的方法被調用了,則忽略,不然reject這個promise 2.3.3.4 若是then方法不是function,那麼fullfill這個promise使用x 2.3.4 若是x不是一個對象或者方法,那麼fullfill這個promise使用x 若是promise產生了環形的嵌套,好比[[Resolve]](promise, thenable)最終喚起了[[Resolve]](promise, thenable),那麼實現建議且並不強求來發現這種循環,而且reject這個promise使用一個TypeError。
const PENDING = 'pending'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; function Promise(executor) { let self = this; self.status = PENDING; self.onFulfilled = [];//成功的回調 self.onRejected = []; //失敗的回調 //PromiseA+ 2.1 function resolve(value) { if (self.status === PENDING) { self.status = FULFILLED; self.value = value; self.onFulfilled.forEach(fn => fn());//PromiseA+ 2.2.6.1 } } function reject(reason) { if (self.status === PENDING) { self.status = REJECTED; self.reason = reason; self.onRejected.forEach(fn => fn());//PromiseA+ 2.2.6.2 } } try { executor(resolve, reject); } catch (e) { reject(e); } } Promise.prototype.then = function (onFulfilled, onRejected) { //PromiseA+ 2.2.1 / PromiseA+ 2.2.5 / PromiseA+ 2.2.7.3 / PromiseA+ 2.2.7.4 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }; let self = this; //PromiseA+ 2.2.7 let promise2 = new Promise((resolve, reject) => { if (self.status === FULFILLED) { //PromiseA+ 2.2.2 //PromiseA+ 2.2.4 --- setTimeout setTimeout(() => { try { //PromiseA+ 2.2.7.1 let x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { //PromiseA+ 2.2.7.2 reject(e); } }); } else if (self.status === REJECTED) { //PromiseA+ 2.2.3 setTimeout(() => { try { let x = onRejected(self.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); } else if (self.status === PENDING) { self.onFulfilled.push(() => { setTimeout(() => { try { let x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); }); self.onRejected.push(() => { setTimeout(() => { try { let x = onRejected(self.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); }); } }); return promise2; } function resolvePromise(promise2, x, resolve, reject) { let self = this; //PromiseA+ 2.3.1 if (promise2 === x) { reject(new TypeError('Chaining cycle')); } if (x && typeof x === 'object' || typeof x === 'function') { let used; //PromiseA+2.3.3.3.3 只能調用一次 try { let then = x.then; if (typeof then === 'function') { //PromiseA+2.3.3 then.call(x, (y) => { //PromiseA+2.3.3.1 if (used) return; used = true; resolvePromise(promise2, y, resolve, reject); }, (r) => { //PromiseA+2.3.3.2 if (used) return; used = true; reject(r); }); }else{ //PromiseA+2.3.3.4 if (used) return; used = true; resolve(x); } } catch (e) { //PromiseA+ 2.3.3.2 if (used) return; used = true; reject(e); } } else { //PromiseA+ 2.3.3.4 resolve(x); } } module.exports = Promise;
resolvePromise 函數即爲根據x的值來決定promise2的狀態的函數,也即標準中的Promise Resolution Procedure;x爲promise2 = promise1.then(onResolved, onRejected)
裏onResolved/onRejected
的返回值,resolve
和reject
其實是promise2
的executor
的兩個實參,由於很難掛在其它的地方,因此一併傳進來。