實現符合 Promise/A+ 規範的Promise

實現一個符合 Promise/A+ 規範的 MyPromise,並實現 resolve、reject、all、race等靜態方法。

promise

  1. 創建Promise 方法
  2. Promise 接收一個 executor 回掉函數
  3. Promise 三個狀態
  • pedding
    • 可以變為 fulfilled 成功態 或者 rejected 失敗態
  • fulfilled
    • 不可改變的成功態
  • rejected
    • 不可改變失敗態
  1. onResolvedCallbacks和onRejectedCallbacks
  • 分別存儲成功 成功和失敗的回調函數
  1. resolve
  • promise專向成功態調用的函數,接收value參數
  1. reject
  • promise轉向失敗態調用的函數,接受reason參數

function Promise(executor) { let self = this; self.status = pending; //存放成功回調的數組 self.onResolvedCallbacks =[]; //存放失敗回調的數組 self.onRejectedCallbacks =[]; function resolve(value) { if(self.status == pending){ self.status = fulfilled; self.value = value;//成功後得到一個值,這個值不能改 self.onResolvedCallbacks.forEach(cb=>cb(self.value))// } } function reject(reason) { if(self.status == pending){ self.status = rejected; self.value = reason; self.onRejectedCallbacks.forEach(cb=>cb(self.value)) } } try{ executor(resolve,reject) }catch (e){ //如果函數執行失敗了,reject這個promise reject(e) }}

Promise.prototype.then

鏈式調用返回一個新的Promise,將第一次的返回值,作為下一次成功回掉函數的參數

  1. onFulfilledonRejected
  • 一個promise.then方法接收兩個參數onFilfiledonRejected
  • 如果成功和失敗的回調沒有傳,則表示這個then沒有任何邏輯,只會把值往後拋
  1. onFulfilled
  • 成功時調用
  • 並把成功的結果傳遞給onFulfilled
  • 不能調用多次
  1. onRejected
  • 失敗時調用
  • 並把失敗的結果傳遞給onRejected
  • 不能調用多次
  1. then會調用多次,之後返回一個新的promise
  • promise2 = promise1.then(onFulfilled, onRejected)
  • 如果 onFulfilledonRejected返回x解析promise 執行 resolvePromise方法

Promise.prototype.then = function (onFulfilled,onRejected) { onFulfilled = typeof onFulfilled == function?onFulfilled:value=>value; onRejected = typeof onRejected == function?onRejected:reason=>{throw reason}; let self = this; let promise2; //當前promise已經是成功態了,onFulfilled直接取值 if(self.status == fulfilled){ return promise2 = new Promise(function (resolve,reject) { try{ let x = onFulfilled(self.value); resolvePromise(promise2,x,resolve,reject) }catch (e){ reject(e) } }); } if(self.status == rejected){ return promise2 = new Promise(function (resolve,reject) { try{ let x = onRejected(self.value); resolvePromise(promise2,x,resolve,reject) }catch (e){ reject(e) } }) } if(self.status == pending){ return promise2 = new Promise(function(resolve,reject){ self.onResolvedCallbacks.push(function(){ try{ let x =onFulfilled(self.value); //如果獲取到了返回值x,會走解析promise的過程 resolvePromise(promise2,x,resolve,reject); }catch(e){ reject(e); } }); self.onRejectedCallbacks.push(function(){ try{ let x =onRejected(self.value); resolvePromise(promise2,x,resolve,reject); }catch(e){ reject(e); } }); }); }};

The Promise resolvePromise 解析方法

  1. 如果x===當前promise2 不能返回當前Promise,那麼會拋出錯誤 new TypeError(循環引用)
  2. x是一個Promise
  • 當前promise2等待x完成,x有可能也是一個Promise 執行resolvePromise()
  1. x 如果不是對象(不包括 null)或者函數,執行 resolve(x)
  2. 獲取 x.then 賦值給 then
  • then 如果是 function
    • 把 x做為 this 調用then,第一個參數是 resolvePromise2,第二個參數是 rejectPromise2
    • resolvePromise2rejectPromise2只有第一次調用有效
    • resolvePromise2參數為 y,執行 resolvePromise(promise, y, resolve, reject)
    • then 如果不是 function
      • 執行resolve(x)

function resolvePromise(promise2,x,resolve,reject){ if(promise2 === x){ return reject(new TypeError(循環引用)); } let called = false;//promise2是否已經resolve 或reject了 if(x instanceof Promise){ if(x.status == pending){ x.then(function(y){ resolvePromise(promise2,y,resolve,reject); },reject); }else{ x.then(resolve,reject); } //x是一個thenable對象或函數,只要有then方法的對象, }else if(x!= null &&((typeof x==object)||(typeof x == function))){ try{ let then = x.then; if(typeof then == function){ //有些promise會同時執行成功和失敗的回調 then.call(x,function(y){ //如果promise2已經成功或失敗了,則不會再處理了 if(called)return; called = true; resolvePromise(promise2,y,resolve,reject) },function(err){ if(called)return; called = true; reject(err); }); }else{ //到此的話x不是一個thenable對象,那直接把它當成值resolve promise2就可以了 resolve(x); } }catch(e){ if(called)return; called = true; reject(e); } }else{ //如果X是一個普通 的值,則用x的值去resolve promise2 resolve(x); }}

Promise.prototype.catch

  1. 直傳失敗的回掉

Promise.prototype.catch = function(onRejected){ this.then(null,onRejected);}

Promise.all

  1. 接收Promise數組,全部完成才會成功,有一個失敗,整個Promise失敗

function gen(times,cb){ let result = [],count=0; return function(i,data){ result[i] = data; if(++count==times){ cb(result); } }}Promise.all = function(promises){ return new Promise(function(resolve,reject){ let done = gen(promises.length,resolve); for(let i=0;i<promises.length;i++){ promises[i].then(function(data){ done(i,data); },reject); } });}

Promise.race

  1. 接收Promise數組,一個成功就成功了,一個失敗就失敗了

Promise.race = function(promises){ return new Promise(function(resolve,reject){ for(let i=0;i<promises.length;i++){ promises[i].then(resolve,reject); } });}

Promise.resolve

Promise.resolve = function(value){ return new Promise(function(resolve){ resolve(value); });}

Promise.reject

Promise.reject = function(reason){ return new Promise(function(resolve,reject){ reject(reason); });}

源碼

參考資料

  • Promise/A+規範
  • Promise/A+規範(英文)
  • JavaScript Promise迷你書(中文版)

推薦閱讀:

可能是最全的 Node.js 9 新特性整理

TAG:Promise | 前端開發 | 前端入門 |