上一篇文章中,咱們介紹了Promise的基本使用,在這篇文章中,咱們試着本身來寫一個Promise,主要是學習Promise的內部機制,學習它的編程思想。javascript
!!!備註:本文寫的很差,僅供本身學習之用,具體的實現過程建議看下面的參考文章。因此本文沒有發佈到博客園首頁和其餘地方html
咱們來看一個正常的使用:java
var p=new Promise(function(resolve,rejcet){ setTimeout(function(){ if(true){ resolve('success'); }else{ rejcet('failure'); } },1000); }); p.then(function(value){ console.log(value); },function(error){ console.log(error); }); //success
接下來咱們就來實現這麼一個Promise.git
先來了解相關的一些術語: es6
解決(fulfill):指一個 promise 成功時進行的一系列操做,如狀態的改變、回調的執行。雖然規範中用 fulfill 來表示解決,但在後世的 promise 實現多以 resolve 來指代之。
拒絕(reject):指一個 promise 失敗時進行的一系列操做。
終值(eventual value):所謂終值,指的是 promise 被解決時傳遞給解決回調的值,因爲 promise 有一次性的特徵,所以當這個值被傳遞時,標誌着 promise 等待態的結束,故稱之終值,有時也直接簡稱爲值(value)。
據因(reason):也就是拒絕緣由,指在 promise 被拒絕時傳遞給拒絕回調的值。github
promise的執行流程如以下:編程
每一個promise後面鏈一個對象該對象包含onfulfiled,onrejected,子promise三個屬性,當父promise 狀態改變完畢,執行完相應的onfulfiled/onfulfiled的時候呢,拿到子promise,在等待這個子promise狀態改變,再執行相應的onfulfiled/onfulfiled。依次循環直到當前promise沒有子promisesegmentfault
將resolve/reject函數和onfulfiled/onrejected放入同一個對象(promise對象)裏面,resolve/reject的時候將value設置this.value=xxx。onfulfiled/onrejected執行的時候呢,onfulfiled(this.value)便可。數組
在這裏避免頭暈,解釋一下,onfulfilled和onrejected指的是then裏面的兩個函數。promise
如圖所示,狀態只能由pengding-->fulfilled,或者由pending-->rejected這樣轉變。
只要這兩種狀況發生,狀態就凝固了,不會再變了,會一直保持這個結果。就算改變已經發生了,你再對Promise
對象添加回調函數,也會當即獲得這個結果。這與事件(Event)徹底不一樣,事件的特色是,若是你錯過了它,再去監聽,是得不到結果的。
一、 首先咱們來寫好咱們的框架
ES6原生的構建方式爲:
// Promise構造函數接收一個executor函數,executor函數執行完同步或異步操做後,調用它的兩個參數resolve和reject var promise = new Promise(function(resolve, reject) { /* 若是操做成功,調用resolve並傳入value 若是操做失敗,調用reject並傳入reason */ })
咱們就按照這種方式來搭好框架
function Promise(callback) { var self = this self.status = 'PENDING' // Promise當前的狀態 self.data = undefined // Promise的值 self.onResolvedCallback = [] // Promise resolve時的回調函數集 self.onRejectedCallback = [] // Promise reject時的回調函數集 callback(resolve, reject) // 執行executor並傳入相應的參數 function resolve(value){ } function rejecte(error){ } } // 添加咱們的then方法 Promise.prototype.then=function(){ }
咱們構造一個Promise函數,並傳入一個回調callback,callback裏面傳入兩個函數做爲參數,一個是resove,一個是reject。並在Promise的原型上加入咱們的then方法。
二、完善框架裏面的內容
框架搭好了,接下來咱們來一點點的完善框架裏面的內容,能夠這麼說,把resolve,reject和then補充完,基本能夠說就是把Promise完成了。
咱們先來完善咱們的resolve和rejected:
function Promise(callback) { var self = this self.status = 'PENDING' // Promise當前的狀態 self.data = undefined // Promise的值 self.onResolvedCallback = [] // Promise resolve時的回調函數集 self.onRejectedCallback = [] // Promise reject時的回調函數集 callback(resolve, reject) // 執行executor並傳入相應的參數 function resolve(value){ if(self.status=='PENDING'){ self.status=='FULFILLED'; self.data=value; // 依次執行成功以後的函數棧 for(var i = 0; i < self.onResolvedCallback.length; i++) { self.onResolvedCallback[i](value) } } } function rejecte(error){ if (self.status === 'PENDING') { self.status = 'REJECTED' self.data = error; // 依次執行失敗以後的函數棧 for(var i = 0; i < self.onRejectedCallback.length; i++) { self.onRejectedCallback[i](error) } } } }
若是是penging,則改變相應的狀態,並把resolve和reject的值保存子data裏面。
接下來咱們實現咱們的then方法:
then方法是Promise的核心,所以這裏會花比較大的篇幅去介紹then:
一個promise的then接受兩個參數:
promise.then(onFulfilled, onRejected)
onFulfilled
和 onRejected
都是可選參數。
onFulfilled
不是函數,其必須被忽略onRejected
不是函數,其必須被忽略onFulfilled
特性若是 onFulfilled
是函數:
promise
執行結束後其必須被調用,其第一個參數爲 promise
的終值,也就是resolve傳過來的值promise
執行結束前其不可被調用onRejected
特性若是 onRejected
是函數:
promise
被拒絕執行後其必須被調用,其第一個參數爲 promise
的據因,也就是reject傳過來的值promise
被拒絕執行前其不可被調用onFulfilled
和 onRejected
只有在執行環境堆棧僅包含平臺代碼時纔可被調用(平臺代碼指引擎、環境以及 promise 的實施代碼)
onFulfilled
和 onRejected
必須被做爲函數調用(即沒有 this
值,在 嚴格模式(strict) 中,函數 this
的值爲 undefined
;在非嚴格模式中其爲全局對象。)
then
方法能夠被同一個 promise
調用屢次
promise
成功執行時,全部 onFulfilled
需按照其註冊順序依次回調promise
被拒絕執行時,全部的 onRejected
需按照其註冊順序依次回調then
方法必須返回一個 promise
對象
promise2 = promise1.then(onFulfilled, onRejected);
onFulfilled
或者 onRejected
返回一個值 x
,則運行下面的 Promise 解決過程:[[Resolve]](promise2, x)
onFulfilled
或者 onRejected
拋出一個異常 e
,則 promise2
必須拒絕執行,並返回拒因 e
onFulfilled
不是函數且 promise1
成功執行, promise2
必須成功執行並返回相同的值onRejected
不是函數且 promise1
拒絕執行, promise2
必須拒絕執行並返回相同的據因不論 promise1
被 reject 仍是被 resolve 時 promise2
都會被 resolve,只有出現異常時纔會被 rejected。
每一個Promise對象均可以在其上屢次調用then方法,而每次調用then返回的Promise的狀態取決於那一次調用then時傳入參數的返回值,因此then不能返回this,由於then每次返回的Promise的結果都有可能不一樣。
接下來咱們來寫咱們的then方法:
Promise.prototype.then = function(onResolved, onRejected) { var self = this var promise2 // 根據標準,若是then的參數不是function,則咱們須要忽略它,此處以以下方式處理 onResolved = typeof onResolved === 'function' ? onResolved : function(value) {} onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {} if (self.status === 'resolved') { // 若是promise1(此處即爲this/self)的狀態已經肯定而且是resolved,咱們調用onResolved // 由於考慮到有可能throw,因此咱們將其包在try/catch塊裏 return promise2 = new Promise(function(resolve, reject) { try { var x = onResolved(self.data) if (x instanceof Promise) { // 若是onResolved的返回值是一個Promise對象,直接取它的結果作爲promise2的結果 x.then(resolve, reject) } resolve(x) // 不然,以它的返回值作爲promise2的結果 } catch (e) { reject(e) // 若是出錯,以捕獲到的錯誤作爲promise2的結果 } }) } // 此處與前一個if塊的邏輯幾乎相同,區別在於所調用的是onRejected函數,就再也不作過多解釋 if (self.status === 'rejected') { return promise2 = new Promise(function(resolve, reject) { try { var x = onRejected(self.data) if (x instanceof Promise) { x.then(resolve, reject) } } catch (e) { reject(e) } }) } if (self.status === 'pending') { // 若是當前的Promise還處於pending狀態,咱們並不能肯定調用onResolved仍是onRejected, // 只能等到Promise的狀態肯定後,才能確實如何處理。 // 因此咱們須要把咱們的**兩種狀況**的處理邏輯作爲callback放入promise1(此處即this/self)的回調數組裏 // 邏輯自己跟第一個if塊內的幾乎一致,此處不作過多解釋 return promise2 = new Promise(function(resolve, reject) { self.onResolvedCallback.push(function(value) { try { var x = onResolved(self.data) if (x instanceof Promise) { x.then(resolve, reject) } } catch (e) { reject(e) } }) self.onRejectedCallback.push(function(reason) { try { var x = onRejected(self.data) if (x instanceof Promise) { x.then(resolve, reject) } } catch (e) { reject(e) } }) }) } } // 爲了下文方便,咱們順便實現一個catch方法 Promise.prototype.catch = function(onRejected) { return this.then(null, onRejected) }
完整代碼以下:
try { module.exports = Promise } catch (e) {} function Promise(executor) { var self = this self.status = 'pending' self.onResolvedCallback = [] self.onRejectedCallback = [] function resolve(value) { if (value instanceof Promise) { return value.then(resolve, reject) } setTimeout(function() { // 異步執行全部的回調函數 if (self.status === 'pending') { self.status = 'resolved' self.data = value for (var i = 0; i < self.onResolvedCallback.length; i++) { self.onResolvedCallback[i](value) } } }) } function reject(reason) { setTimeout(function() { // 異步執行全部的回調函數 if (self.status === 'pending') { self.status = 'rejected' self.data = reason for (var i = 0; i < self.onRejectedCallback.length; i++) { self.onRejectedCallback[i](reason) } } }) } try { executor(resolve, reject) } catch (reason) { reject(reason) } } function resolvePromise(promise2, x, resolve, reject) { var then var thenCalledOrThrow = false if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise!')) } if (x instanceof Promise) { if (x.status === 'pending') { //because x could resolved by a Promise Object x.then(function(v) { resolvePromise(promise2, v, resolve, reject) }, reject) } else { //but if it is resolved, it will never resolved by a Promise Object but a static value; x.then(resolve, reject) } return } if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) { try { then = x.then //because x.then could be a getter if (typeof then === 'function') { then.call(x, function rs(y) { if (thenCalledOrThrow) return thenCalledOrThrow = true return resolvePromise(promise2, y, resolve, reject) }, function rj(r) { if (thenCalledOrThrow) return thenCalledOrThrow = true return reject(r) }) } else { resolve(x) } } catch (e) { if (thenCalledOrThrow) return thenCalledOrThrow = true return reject(e) } } else { resolve(x) } } Promise.prototype.then = function(onResolved, onRejected) { var self = this var promise2 onResolved = typeof onResolved === 'function' ? onResolved : function(v) { return v } onRejected = typeof onRejected === 'function' ? onRejected : function(r) { throw r } if (self.status === 'resolved') { return promise2 = new Promise(function(resolve, reject) { setTimeout(function() { // 異步執行onResolved try { var x = onResolved(self.data) resolvePromise(promise2, x, resolve, reject) } catch (reason) { reject(reason) } }) }) } if (self.status === 'rejected') { return promise2 = new Promise(function(resolve, reject) { setTimeout(function() { // 異步執行onRejected try { var x = onRejected(self.data) resolvePromise(promise2, x, resolve, reject) } catch (reason) { reject(reason) } }) }) } if (self.status === 'pending') { // 這裏之因此沒有異步執行,是由於這些函數必然會被resolve或reject調用,而resolve或reject函數裏的內容已經是異步執行,構造函數裏的定義 return promise2 = new Promise(function(resolve, reject) { self.onResolvedCallback.push(function(value) { try { var x = onResolved(value) resolvePromise(promise2, x, resolve, reject) } catch (r) { reject(r) } }) self.onRejectedCallback.push(function(reason) { try { var x = onRejected(reason) resolvePromise(promise2, x, resolve, reject) } catch (r) { reject(r) } }) }) } } Promise.prototype.catch = function(onRejected) { return this.then(null, onRejected) } Promise.deferred = Promise.defer = function() { var dfd = {} dfd.promise = new Promise(function(resolve, reject) { dfd.resolve = resolve dfd.reject = reject }) return dfd }
本文沒有寫好,有點頭暈,因此具體的實現過程仍是建議看下面的參考文章。
參考: