你能白瞟到的最「善解人意」的Promise實現

前沿

俗話說站在前輩巨擘的肩上,才能尿的更遠。做爲一個頂風尿三丈的小人物,在拜讀了巨擘大咖們寫的promise實現以後,全身經絡通暢,如被先輩們用金手指點中了百會穴。至此之後,運行大小週天比往常更熟練了幾分。然而,肩井穴,涌泉穴,每日亥時,都會隱隱做痛。思來想去,大概時先前巨擘的文章精妙,我一時沒法所有領悟其中奧妙。固苦心感悟,方得此篇。不敢與前輩比肩,只當部分補充而已es6

直男不懂鋪墊,因此直接幹

這裏咱們用es6來實現,這樣結構比較明顯,若是有對es6不太熟悉的朋友,能夠看看阮一峯老師的ECMAScript 6 入門web

class myPromise {
 constructor(executor){  this.value = null;  this.reason = null;  const resolve = value =>{  this.value = value;  }  const reject = reason => {  this.reason = reason;  }  try {  executor(resolve,reject)  } catch (e) {  reject(e)  }  }  then(onFulfilled,onRejected){  onFulfilled(this.value)  onRejected(this.reason)  }  } 複製代碼

代碼解析:npm

  1. myPromise是一個構造函數,參數是一個高階函數,接受兩個內部函數resolve,reject
  2. myPromise的實例均可以調用then方法,then方法的第一個參數接受resolve的返回,第二個參數接受reject的返回

學武功的第一步是(自宮)對比

起手式

觀察後發現:咱們實現的myPormise和Promise運行的結果一致(good guy!),只是有一個小問題,咱們是先調用的p1的then,可是p1的then返回倒是在p2的then返回以後。咱們保留疑問,繼續淦!!!json

resolve/reject的單一性

意思就是當一個promise中的resolve或者reject執行了以後,那以後resolve/reject都再也不執行數組

觀察以後,發現這就不對了promise

  1. 別人家的promise只返回了一個'p1-resolve',而我們家的promise返回了'p2-resolve2'和'p2-reject1'
  2. 別家的promise和我們家的promise不同就算了,咋還少了一個'p2-resolve1'呢?這裏的緣由是reslove方法裏面,咱們用一個內部變量this.value保存了resolve的值,當執行resolve('p2-resolve1')以後,再執行resolve('p2-resolve2')時,this.value就被後者從新賦值了。而後再執行到then函數時,天然而然'p2-resolve1'就消失了。
  3. 怎麼修改呢? 這裏咱們引入一個內部狀態的概念來處理這個問題,初始狀態咱們設置爲'pending',它只有一次改變狀態的機會,它能夠變成pending->fulfilled或者pending->rejected,一旦改變以後,就不在變化。(是否是像極了寶可夢的進化)。
  4. 另外爲了保證resolve/reject執行的惟一性,當狀態不在是pending時,resolve/reject就不執行

因此...(就決定是你了,皮卡丘!!!)異步

class myPromise {
 constructor(executor){ + this.state = 'pending'; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  const resolve = value => { + if(this.state === 'pending'){ + this.state = 'fulfilled';  this.value = value; + }  }  const reject = reason => { + if(this.state === 'pending'){ + this.state = 'rejected';  this.reason = reason; + }  }  try {  executor(resolve,reject)  } catch (e) {  reject(e)  }  }  then(onFulfilled,onRejected){ + if(this.state === 'fulfilled'){  onFulfilled(this.value) + } + if(this.state === 'rejected') {  onRejected(this.reason) + }  }  } 複製代碼

修改以後,再觀察,我們家的promise又正常了一些。編輯器

promise的異步執行

咱們稍微清理一下咱們的測試代碼,使它看上去清爽天然函數

清理完以後。咱們加上異步測試

經過觀察,咱們發現,咱們的promise沒有任何打印

  1. 仔細思考以後,咱們能夠想到,當resolve尚未執行的時候,then函數已經執行了,而這時的state爲'pending',因此then函數裏面不會有任何執行
  2. 咱們怎麼處理這種狀況呢?首先能夠想到,當resolve/reject的時候,這個時候執行then時的state爲'pending',而這個時候,咱們不知道以後到底時執行resolve呢?仍是reject,因此咱們只有將全部的then的全部的參數(onFulfilled/onRejected)都暫存起來,以待以後的state改變以後執行對應的方法(onFulfilled/onRejected)
  3. 當狀態改變以後,當即執行暫存的對應的方法

基於上面所說,咱們修改咱們的promise

class myPromise {
 constructor(executor){  this.state = 'pending'; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null; + this.onFulfilledCallbacks = []; + this.onRejectedCallbacks = [];  const resolve = value =>{  if(this.state === 'pending'){  this.state = 'fulfilled';  this.value = value; + this.onFulfilledCallbacks.forEach(fn=>fn(value))  }  }  const reject = reason => {  if(this.state === 'pending'){  this.state = 'rejected';  this.reason = reason; + this.onRejectedCallbacks.forEach(fn=>fn(reason))  }  }  try {  executor(resolve,reject)  } catch (e) {  reject(e)  }  }  then(onFulfilled,onRejected){  if(this.state === 'fulfilled'){  onFulfilled(this.value)  }  if(this.state === 'rejected') {  onRejected(this.reason)  } + if(this.state === 'pending') { + this.onFulfilledCallbacks.push(onFulfilled) + this.onRejectedCallbacks.push(onRejected) + }  }  } 複製代碼

修改以後,咱們看看結果 觀察以後,發現咱們的promise可以正常的顯示then回調了,並且還有意外收穫,仔細觀察咱們發現,p1.then和p2.then打印的順序和調用時的順序一致了!!!

同步異步一致性

不論promise裏面的resolve/reject是同步或者異步,咱們都但願then返回的執行表現一致 咱們建立一個執行對比

通過觀察,咱們能夠發現

  1. 別人家的promise,不論resolve是同步的仍是異步的,then返回都是異步的
  2. 我們家的promise,當resolve是異步的,then返回是異步的,當resolve是同步的返回就是同步的

那麼怎麼改呢?咱們的目的是要保持then的執行一致,因此只能把所有的then修改爲異步的,緣由在上一節已經說明了 咱們來修改一下我們家的promise

class myPromise {
 constructor(executor) {  this.state = 'pending'; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = value => {  if (this.state === 'pending') {  this.state = 'fulfilled';  this.value = value;  this.onFulfilledCallbacks.forEach(fn => fn(value))  }  }  const reject = reason => {  if (this.state === 'pending') {  this.state = 'rejected';  this.reason = reason;  this.onRejectedCallbacks.forEach(fn => fn(reason))  }  }  try {  executor(resolve, reject)  } catch (e) {  reject(e)  }  }  then(onFulfilled, onRejected) {  if (this.state === 'fulfilled') { + setTimeout(()=>{  onFulfilled(this.value) + })  }  if (this.state === 'rejected') { + setTimeout(()=>{  onRejected(this.reason) + })  }  if (this.state === 'pending') { + this.onFulfilledCallbacks.push((value)=>setTimeout(()=>{onFulfilled(value)})) + this.onRejectedCallbacks.push((reason)=>setTimeout(()=>{onRejected(reason)}))  }  }  } 複製代碼

而後來看看執行

如今我們家的promise就更像別人家的了

爲何是數組

細心的小夥伴會發現this.onFulfilledCallbacks和this.onRejectedCallbacks是數組,在then方法裏面,當state === 'pending'時,咱們把onFulfilled和onRejected添加再數組進數組,而不是直接賦值給this.onFulfilledCallbacks/this.onRejectedCallbacks。會以爲這裏直接賦值好像也沒有什麼問題。

咱們修改一下咱們promise直接用變量存儲

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value; - this.onFulfilledCallbacks.forEach((fn) => fn(value)); + this.onFulfilledCallbacks(value);  }  };  const reject = (reason) => {  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  }  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  if (this.state === "fulfilled") {  setTimeout(() => {  onFulfilled(this.value)  })  }  if (this.state === "rejected") {  setTimeout(() => {  onRejected(this.reason)  })  }  if (this.state === "pending") { - this.onFulfilledCallbacks.push((value)=>setTimeout(()=>{onFulfilled(value)})); + this.onFulfilledCallbacks = (value)=>setTimeout(()=>{onFulfilled(value)});  this.onRejectedCallbacks.push(onRejected);  }  }  } 複製代碼

通過觀察咱們發現:

  1. 別人家的promise,兩個then回調的onFulfilled都正常執行了,我們家的只執行了第二個then回調的
  2. 我們家的promise的問題是,第二個then執行的時候,覆蓋了第一個then的onFulfilledCallbacks賦值。因此這裏只會執行第二個then回調的onFulfilled

咱們把代碼回滾到上一節,而後進入下一節

鏈式調用

then方法不管什麼時候都返回一個promise實例

咱們仔細觀察一下

  1. 別人家的promise是執行了第一個then方法以後,又成功的執行了第二個then方法
  2. 我們家的promise是執行了第一個then方法以後,第二個then方法就報錯了
  3. 由於我們家的promise的then方法沒有返回一個promise對象

咱們按着咱們的分析來修改一下咱們的promise

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  }  };  const reject = (reason) => {  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  }  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  if (this.state === "fulfilled") {  setTimeout(() => {  onFulfilled(this.value)  })  }  if (this.state === "rejected") {  setTimeout(() => {  onRejected(this.reason)  })  }  if (this.state === "pending") {  this.onFulfilledCallbacks.push((value)=>setTimeout(()=>{onFulfilled(value)}));  this.onFulfilledCallbacks = (value)=>setTimeout(()=>{onFulfilled(value)});  } + return new myPromise((resolve,reject)=>{ + resolve() + })  }  } 複製代碼

修改完成以後,咱們執行看看

通過觀察咱們能夠發現

  1. p2-resolve-then2已經成功的打印出來了,只是和別人家的promise打印的位置不太對

第二個then的返回值問題

第二個then的onFulfilled的參數是第一個onFuifilled的return值

因此咱們修改一下咱們執行代碼

這裏有一個小tips,這裏用了並的邏輯運算符,console.log()這個函數返回一個undefined,因此在前面取了非

花開兩朵各表一枝,

咱們觀察發現

  1. 別人家的promise的第二個then可以正常的接收到第一個then傳遞過來的值
  2. 我們家的promis卻不能,其實也不奇怪,我們家的promise在then裏面返回的promise中的resolve方法中沒有參數!!!

咱們按着這個思路,來改改我們家的promise

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  }  };  const reject = (reason) => {  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  }  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  const promise2 = new myPromise((resolve, reject) => {  if (this.state === "fulfilled") {  setTimeout(() => { + // 萬一onFulfilled方法報錯,咱們用trycatch捕獲一下 + try { + let x = onFulfilled(this.value); + resolve(x) + } catch (error) { + reject(error) + }  })  }  if (this.state === "rejected") {  setTimeout(() => { + try { + let x = onRejected(this.reason); + //這裏暫時有點問題,咱們先這麼寫,由於這裏比較符合邏輯 + reject(x) + } catch (error) { + reject(error) + }  })  }  if (this.state === "pending") {  this.onFulfilledCallbacks.push(value => { + try { + let x = onFulfilled(value) + resolve(x) + } catch (error) { + reject(error) + }  });  this.onRejectedCallbacks.push(reason => { + try { + let x = onRejected(reason) + //這裏暫時有點問題,咱們先這麼寫,由於這裏比較符合邏輯 + reject(x) + } catch (error) { + reject(error) + }  });  }  })  return promise2;  }  } 複製代碼

最後來看看結果

觀察能夠返現,我們家的promise已經和別人家的promise已經愈來愈像了(牛頭人警告!)

then函數的onRejected的返回會被下一個then函數的onFulfilled方法接受

咱們來看看例子

仔細觀察咱們發現

  1. 別人家的promise的then函數鏈的執行是 p1-reject-then1(第一個then的onRejected)=> p1-resolve-then2(第二個then的onFulfilled)
  2. 我們家的promise的then函數鏈的執行是 p2-reject-then1(第一個then的onRejected)=> p2-reject-then2(第二個then的onRejected)
  3. 這裏的不一樣是promise的reject不須要傳遞(這是約定,不要爲我爲啥)

我畫了一個圖

因此咱們來修改我們家的promise

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  }  };  const reject = (reason) => {  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  }  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  const promise2 = new myPromise((resolve, reject) => {  if (this.state === "fulfilled") {  setTimeout(() => {  // 萬一onFulfilled方法報錯,咱們用trycatch捕獲一下  try {  let x = onFulfilled(this.value);  resolve(x)  } catch (error) {  reject(error)  }  })  }  if (this.state === "rejected") {  setTimeout(() => {  try {  let x = onRejected(this.reason); - //這裏暫時有點問題,咱們先這麼寫,由於這裏比較符合邏輯 - reject(x) + resolve(x)  } catch (error) {  reject(error)  }  })  }  if (this.state === "pending") {  this.onFulfilledCallbacks.push(value => {  try {  let x = onFulfilled(value)  resolve(x)  } catch (error) {  reject(error)  }  });  this.onRejectedCallbacks.push(reason => {  try {  let x = onRejected(reason) - //這裏暫時有點問題,咱們先這麼寫,由於這裏比較符合邏輯 - reject(x) + reslove(x)  } catch (error) {  reject(error)  }  });  }  })  return promise2;  }  } 複製代碼

修改完了,咱們來看看結果

bingo!!! 我們家的promise又像了別人家的promise幾分

調整一下結構

大致上的 結構已經完成了,接下來咱們要調整一下,方便接下來的對比

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  }  };  const reject = (reason) => {  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  }  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  const promise2 = new myPromise((resolve, reject) => {  if (this.state === "fulfilled") {  setTimeout(() => {  // 萬一onFulfilled方法報錯,咱們用trycatch捕獲一下  try {  let x = onFulfilled(this.value); - reslove(x) + resolvePromise(promise,x,resolve,reject)  } catch (error) {  reject(error)  }  })  }  if (this.state === "rejected") {  setTimeout(() => {  try {  let x = onRejected(this.reason); - reslove(x) + resolvePromise(promise,x,resolve,reject)  } catch (error) {  reject(error)  }  })  }  if (this.state === "pending") {  this.onFulfilledCallbacks.push(value => {  try {  let x = onFulfilled(value) - reslove(x) + resolvePromise(promise,x,resolve,reject)  } catch (error) {  reject(error)  }  });  this.onRejectedCallbacks.push(reason => {  try {  let x = onRejected(reason) - reslove(x) + resolvePromise(promise,x,resolve,reject)  } catch (error) {  reject(error)  }  });  }  })  return promise2;  }  } + function resolvePromise(promise2,x,resovle,reject) { + resolve(x) + } 複製代碼

咱們建立了一個函數resolvePromise 專門來處理resolve相關的邏輯,由於這部分高度複用,因此咱們把它單獨抽離成一個函數,目前這個函數裏面仍是隻執行了resolve(x)

當onFulfilled/onRejected的返回值是一個promise對象時

觀察能夠發現,

  1. 別人家的promise正常的將promise裏面的resolve值傳遞給了第二個then方法
  2. 我們家的promise,像一個鐵憨憨一下,把promise實例當一個值返回了

這裏我們要弄懂,promise鏈式調用,具體的實現邏輯

解析:

  1. 通常狀況下,咱們調用resolve傳遞的是當前then(onFulfilled,onRejected)的onFulfilled和onRejected的返回
  2. 當onFulfilled和onRejected的返回是一個promise實例時,resolve傳遞的是當前這個實例的then(onFullfilled,onRejected)中的onFullfilled/onRejected的返回

根據咱們的理解,來修改我們家的promise

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  }  };  const reject = (reason) => {  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  }  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  const promise2 = new myPromise((resolve, reject) => {  if (this.state === "fulfilled") {  setTimeout(() => {  // 萬一onFulfilled方法報錯,咱們用trycatch捕獲一下  try {  let x = onFulfilled(this.value);  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })  }  if (this.state === "rejected") {  setTimeout(() => {  try {  let x = onRejected(this.reason);  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })  }  if (this.state === "pending") {  this.onFulfilledCallbacks.push(value => {  try {  let x = onFulfilled(value)  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  });  this.onRejectedCallbacks.push(reason => {  try {  let x = onRejected(reason)  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  });  }  })  return promise2;  }  }  function resolvePromise(promise2, x, resolve, reject) { + if (x instanceof myPromise) { + if (x.state === 'pending') { + x.then((y) => { + resolvePromise(promise2, y, resolve, reject) + }, reject) + } else { + x.then(resolve, reject) + } + } else {  resolve(x) + }  } 複製代碼

修改了以後,咱們來看看

觀察之後,發現我們家的promise也愈來愈標準化了

特殊中的特殊狀況

當resolve返回的是一個包含then函數的對象,或者函數時,要執行一次這個then函數

首先咱們來看看對比

通過觀察咱們能夠發現,

  1. 別人家的promise是成功的返回了,fn1的入參
  2. 而我們家的promise卻吧整個對象都返回了
  3. 別人家的promise,調用了fn1和fn2,可是隻執行了排在前面的fn1,是由於fn1和fn2和resolve/reject同樣都有單一執行原則
  4. 小問題,若是then裏面的fn1/fn2返回的是一個promise對象呢?這個問題仔細想一想?
  5. 結論就是,咱們還要按照promise的標準再一次處理一下

咱們按照咱們的想法來完善我們家的promise

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  }  };  const reject = (reason) => {  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  }  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  const promise2 = new myPromise((resolve, reject) => {  if (this.state === "fulfilled") {  setTimeout(() => {  // 萬一onFulfilled方法報錯,咱們用trycatch捕獲一下  try {  let x = onFulfilled(this.value);  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })  }  if (this.state === "rejected") {  setTimeout(() => {  try {  let x = onRejected(this.reason);  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })  }  if (this.state === "pending") {  this.onFulfilledCallbacks.push(value => {  try {  let x = onFulfilled(value)  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  });  this.onRejectedCallbacks.push(reason => {  try {  let x = onRejected(reason)  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  });  }  })  return promise2;  }  }  function resolvePromise(promise2, x, resolve, reject) {  if (x instanceof myPromise) {  if (x.state === 'pending') {  x.then((y) => {  resolvePromise(promise2, y, resolve, reject)  }, reject)  } else {  x.then(resolve, reject)  } + } else if(x && (typeof x === 'object'|| typeof x === 'function')){ + let called = false; + try { + let then = x.then; + if(typeof then === 'function'){ + then.call(x,(y)=>{ + if(called) return; + called = true; + resolvePromise(promise2,y,resolve,reject); + },(e)=>{ + if(called) return; + called = true; + reject(e) + }) + }else{ + resolve(x) + } + } catch (error) { + if(called) return; + called = true; + reject(error) + } + }  else {  resolve(x)  }  } 複製代碼

修改完了以後,咱們來看看結果

固然返回一個有then方法的函數結果也是同樣的

能夠看見我們家的promise,又一次完成進化,如今快成長成一個獨當一面的promise了

處理極端狀況

then(onFulfilled,onRejected)中的onFulFilled返回的是當前的then()

咱們來看看對比

觀察能夠發現

  1. 別人家的promise報錯了
  2. 我們家的promise沒有反應
  3. 我們家的promise沒有反應,是由於它在無限的執行then,陷入了死循環

咱們畫個圖

這是一個正常狀況

當2這onFulfilled返回的是上面整個then時,就陷入了自我循環

因此這裏,咱們阻止一下自我循環

class myPromise {
 ...  }  function resolvePromise(promise2, x, resolve, reject) { + if(promise2===x) { + return reject(new TypeError('自我循環')) + }  if (x instanceof myPromise) {  ...  }  } 複製代碼

當then(onFulfilled,onRejected)中的onFulfilled,onRejected不爲function時

這裏是約定,因此沒有啥理由

咱們來加上

then(onFulfilled, onRejected) {
+ onFulfilled = typeof onFulfilled === 'function'? onFulfilled:y=>y; + onRejected = typeof onRejected === 'function'? onRejected:y=>{throw y;}  let promise2 = new myPromise((resolve, reject) => { 複製代碼

當一個promise的reslove的參數是一個promise的時候

暫時不知道爲何,有知道的大佬說明一下 這個也是一個約定,咱們來看一個例子

觀察以後,能夠發現,resolve的promise傳遞是reslove的值,而reject是直接傳遞promise實例 因此咱們來改造我們家的promise

const resolve = (value) => {
+ if (value instanceof myPromise) { + return value.then(resolve, reject) + }  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  }  }; 複製代碼

到這裏,我們家的promise,大概就是這個樣子的

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (value instanceof myPromise) {  return value.then(resolve, reject)  }  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  }  };  const reject = (reason) => {  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  }  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : y => y;  onRejected = typeof onRejected === 'function' ? onRejected : y => { throw y; }  const promise2 = new myPromise((resolve, reject) => {  if (this.state === "fulfilled") {  setTimeout(() => {  // 萬一onFulfilled方法報錯,咱們用trycatch捕獲一下  try {  let x = onFulfilled(this.value);  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })   }  if (this.state === "rejected") {  setTimeout(() => {  try {  let x = onRejected(this.reason);  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })  }  if (this.state === "pending") {  this.onFulfilledCallbacks.push(value => {  setTimeout(() => {  try {  let x = onFulfilled(value)  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })  });  this.onRejectedCallbacks.push(reason => {  setTimeout(() => {  try {  let x = onRejected(reason)  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })  });  }  })  return promise2;  }  }  function resolvePromise(promise2, x, resolve, reject) {  if (x === promise2) {  return new TypeError('自我循環')  }  if (x instanceof myPromise) {  if (x.state === 'pending') {  x.then((y) => {  resolvePromise(promise2, y, resolve, reject)  }, reject)  } else {  x.then(resolve, reject)  }  } else if (x && (typeof x === 'object' || typeof x === 'function')) {  let called = false;  try {  let then = x.then;  if (typeof then === 'function') {  then.call(x, (y) => {  if (called) return;  called = true;  resolvePromise(promise2, y, resolve, reject);  }, (e) => {  if (called) return;  called = true;  reject(e)  })  } else {  resolve(x)  }  } catch (error) {  if (called) return;  called = true;  reject(error)  }  }  else {  resolve(x)  }  }  複製代碼

最後用promises-aplus-tests測試一下咱們的promise

npm init
 npm i promises-aplus-tests -D 複製代碼

修改一下package.json

"scripts": {
 // 後面接你的文件  "test": "promises-aplus-tests ./src/index.js"  }, 複製代碼

執行

npm run test
複製代碼

最後發現有40測試沒經過

少年,你還記得一招從天而降的掌法嗎?

這裏,其餘的文章會告訴這是promise的規範,就彷彿回到了小學時代,我懵懵懂懂的問老師問題時,老師告訴我只須要記住就好了。 可是,我拒絕!!!

咱們來看一個極端的例子

爲何不同的呢?

究其根本緣由,resolvePromise返回了一個狀態爲fuifilled的promise

在promise內部的resolvePromise()方法內,直接執行了x.then(reslove,reject)

因此把custom thenable當成了值,錯誤的返回了

這裏怎麼處理呢

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (value instanceof myPromise) {  return value.then(resolve, reject);  } + setTimeout(() => {  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  } + })   };  const reject = (reason) => { + setTimeout(()=>{  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  } + })  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : y => y;  onRejected = typeof onRejected === 'function' ? onRejected : y => { throw y; }  const promise2 = new myPromise((resolve, reject) => {  if (this.state === "fulfilled") {  setTimeout(() => {  // 萬一onFulfilled方法報錯,咱們用trycatch捕獲一下  try {  let x = onFulfilled(this.value);  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })   }  if (this.state === "rejected") {  setTimeout(() => {  try {  let x = onRejected(this.reason);  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  }  })  }  if (this.state === "pending") {  this.onFulfilledCallbacks.push(value => { - setTimeout(() => {  try {  let x = onFulfilled(value)  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  } - })  });  this.onRejectedCallbacks.push(reason => { - setTimeout(() => {  try {  let x = onRejected(reason)  resolvePromise(promise2, x, resolve, reject)  } catch (error) {  reject(error)  } - })  });  }  })  return promise2;  } } function resolvePromise(promise2, x, resolve, reject) {  if (x === promise2) {  return reject(new TypeError('自我循環'))  }  if (x instanceof myPromise) {  if (x.state === 'pending') {  x.then((y) => {  resolvePromise(promise2, y, resolve, reject)  }, reject)  } else {  x.then(resolve, reject)  }  } else if (x && (typeof x === 'object' || typeof x === 'function')) {  let called = false;  try {  let then = x.then;  if (typeof then === 'function') {  then.call(x, (y) => {  if (called) return;  called = true;  resolvePromise(promise2, y, resolve, reject);  }, (e) => {  if (called) return;  called = true;  reject(e)  })  } else {  resolve(x)  }  } catch (error) {  if (called) return;  called = true;  reject(error)  }  }  else {  resolve(x)  } } 複製代碼

咱們把全部的resolve/reject都改爲異步觸發

最後的最後

咱們執行 執行

npm run test
複製代碼

終於經過了所有的測試用例了

最終代碼

class myPromise {
 constructor(executor) {  this.state = "pending"; //內部狀態爲pending,resolve,reject  this.value = null;  this.reason = null;  this.onFulfilledCallbacks = [];  this.onRejectedCallbacks = [];  const resolve = (value) => {  if (value instanceof myPromise) {  return value.then(resolve, reject);  }  setTimeout(() => {  if (this.state === "pending") {  this.state = "fulfilled";  this.value = value;  this.onFulfilledCallbacks.forEach((fn) => fn(value));  }  });  };  const reject = (reason) => {  setTimeout(() => {  if (this.state === "pending") {  this.state = "rejected";  this.reason = reason;  this.onRejectedCallbacks.forEach((fn) => fn(reason));  }  });  };  try {  executor(resolve, reject);  } catch (e) {  reject(e);  }  }  then(onFulfilled, onRejected) {  onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (y) => y;  onRejected =  typeof onRejected === "function"  ? onRejected  : (y) => {  throw y;  };  const promise2 = new myPromise((resolve, reject) => {  if (this.state === "fulfilled") {  setTimeout(() => {  // 萬一onFulfilled方法報錯,咱們用trycatch捕獲一下  try {  let x = onFulfilled(this.value);  resolvePromise(promise2, x, resolve, reject);  } catch (error) {  reject(error);  }  });  }  if (this.state === "rejected") {  setTimeout(() => {  try {  let x = onRejected(this.reason);  resolvePromise(promise2, x, resolve, reject);  } catch (error) {  reject(error);  }  });  }  if (this.state === "pending") {  this.onFulfilledCallbacks.push((value) => {  try {  let x = onFulfilled(value);  resolvePromise(promise2, x, resolve, reject);  } catch (error) {  reject(error);  }  });  this.onRejectedCallbacks.push((reason) => {  try {  let x = onRejected(reason);  resolvePromise(promise2, x, resolve, reject);  } catch (error) {  reject(error);  }  });  }  });  return promise2;  } } function resolvePromise(promise2, x, resolve, reject) {  if (x === promise2) {  return reject(new TypeError("自我循環"));  }  if (x instanceof myPromise) {  if (x.state === "pending") {  x.then((y) => {  resolvePromise(promise2, y, resolve, reject);  }, reject);  } else {  x.then(resolve, reject);  }  } else if (x && (typeof x === "object" || typeof x === "function")) {  let called = false;  try {  let then = x.then;  if (typeof then === "function") {  then.call(  x,  (y) => {  if (called) return;  called = true;  resolvePromise(promise2, y, resolve, reject);  },  (e) => {  if (called) return;  called = true;  reject(e);  }  );  } else {  resolve(x);  }  } catch (error) {  if (called) return;  called = true;  reject(error);  }  } else {  resolve(x);  } }  myPromise.deferred = function () {  let defer = {};  defer.promise = new myPromise((resolve, reject) => {  defer.resolve = resolve;  defer.reject = reject;  });  return defer; };  module.exports = myPromise; 複製代碼

本文使用 mdnice 排版

相關文章
相關標籤/搜索