成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

[實(shí)踐系列]Promises/A+規(guī)范

hqman / 2427人閱讀

摘要:前言實(shí)踐系列主要是讓我們通過(guò)實(shí)踐去加深對(duì)一些原理的理解。雖然規(guī)范中用來(lái)表示解決,但在后世的實(shí)現(xiàn)多以來(lái)指代之。是一個(gè)擁有方法的對(duì)象或函數(shù),其行為符合本規(guī)范。實(shí)踐中要確保和方法異步執(zhí)行,且應(yīng)該在方法被調(diào)用的那一輪事件循環(huán)之后的新執(zhí)行棧中執(zhí)行。

前言

[實(shí)踐系列] 主要是讓我們通過(guò)實(shí)踐去加深對(duì)一些原理的理解。

實(shí)踐系列-前端路由

實(shí)踐系列-Babel原理

有興趣的同學(xué)可以關(guān)注 實(shí)踐系列 。 求star求follow~

什么是Promise ?
Promise是JS異步編程中的重要概念,異步抽象處理對(duì)象,是目前比較流行Javascript異步編程解決方案之一
Promises/A+ 規(guī)范
為實(shí)現(xiàn)者提供一個(gè)健全的、可互操作的 JavaScript promise 的開(kāi)放標(biāo)準(zhǔn)。
術(shù)語(yǔ)

解決 (fulfill) : 指一個(gè) promise 成功時(shí)進(jìn)行的一系列操作,如狀態(tài)的改變、回調(diào)的執(zhí)行。雖然規(guī)范中用 fulfill 來(lái)表示解決,但在后世的 promise 實(shí)現(xiàn)多以 resolve 來(lái)指代之。

拒絕(reject) : 指一個(gè) promise 失敗時(shí)進(jìn)行的一系列操作。

拒因 (reason) : 也就是拒絕原因,指在 promise 被拒絕時(shí)傳遞給拒絕回調(diào)的值。

終值(eventual value) : 所謂終值,指的是 promise 被解決時(shí)傳遞給解決回調(diào)的值,由于 promise 有一次性的特征,因此當(dāng)這個(gè)值被傳遞時(shí),標(biāo)志著 promise 等待態(tài)的結(jié)束,故稱之終值,有時(shí)也直接簡(jiǎn)稱為值(value)。

Promise : promise 是一個(gè)擁有 then 方法的對(duì)象或函數(shù),其行為符合本規(guī)范。

thenable : 是一個(gè)定義了 then 方法的對(duì)象或函數(shù),文中譯作“擁有 then 方法”。

異常(exception) : 是使用 throw 語(yǔ)句拋出的一個(gè)值。

基本要求
下面我們先來(lái)講述Promise/A+ 規(guī)范的幾個(gè)基本要求。
1. Promise的狀態(tài)

一個(gè)Promise的當(dāng)前狀態(tài)必須是以下三種狀態(tài)中的一種: 等待狀態(tài)(Pending) 執(zhí)行狀態(tài)(Fulfilled)拒絕狀態(tài)(Rejected)。

const PENDING = "pending";

const FULFILLED = "fulfilled";

const REJECTED = "rejected";

等待狀態(tài) (Pending)

處于等待態(tài)時(shí),promise 需滿足以下條件:

可以遷移至執(zhí)行態(tài)或拒絕態(tài)

 if (this.state === PENDING) {
     this.state = FULFILLED || REJECTED ;
 }

執(zhí)行狀態(tài) (Fulfilled)

處于執(zhí)行態(tài)時(shí),promise 需滿足以下條件:

不能遷移至其他任何狀態(tài)

必須擁有一個(gè)不可變的終值

 this.value = value;

拒絕狀態(tài) (Rejected)

處于拒絕態(tài)時(shí),promise 需滿足以下條件:

不能遷移至其他任何狀態(tài)

必須擁有一個(gè)不可變的據(jù)因

 this.reason = reason;

這里的不可變指的是恒等(即可用 === 判斷相等),而不是意味著更深層次的不可變(譯者注:蓋指當(dāng) value 或 reason 不是基本值時(shí),只要求其引用地址相等,但屬性值可被更改)

2. Then 方法

一個(gè) promise 必須提供一個(gè) then 方法以訪問(wèn)其當(dāng)前值、終值和據(jù)因。

promise 的 then 方法接受兩個(gè)參數(shù):

promise.then(onFulfilled, onRejected)

參數(shù)可選

onFulfilled 和 onRejected 都是可選參數(shù)。

如果 onFulfilled 不是函數(shù),其必須被忽略

如果 onRejected 不是函數(shù),其必須被忽略

onFulfilled 特性

如果 onFulfilled 是函數(shù):

當(dāng) promise 執(zhí)行結(jié)束后其必須被調(diào)用,其第一個(gè)參數(shù)為 promise 的終值

在 promise 執(zhí)行結(jié)束前其不可被調(diào)用

其調(diào)用次數(shù)不可超過(guò)一次

onRejected 特性

如果 onRejected 是函數(shù):

當(dāng) promise 被拒絕執(zhí)行后其必須被調(diào)用,其第一個(gè)參數(shù)為 promise 的據(jù)因

在 promise 被拒絕執(zhí)行前其不可被調(diào)用

其調(diào)用次數(shù)不可超過(guò)一次

調(diào)用時(shí)機(jī)

onFulfilled 和 onRejected 只有在執(zhí)行環(huán)境堆棧僅包含平臺(tái)代碼時(shí)才可被調(diào)用 注1

注1 這里的平臺(tái)代碼指的是引擎、環(huán)境以及 promise 的實(shí)施代碼。實(shí)踐中要確保 onFulfilled 和 onRejected 方法異步執(zhí)行,且應(yīng)該在 then 方法被調(diào)用的那一輪事件循環(huán)之后的新執(zhí)行棧中執(zhí)行。

這個(gè)事件隊(duì)列可以采用“宏任務(wù)(macro - task)”機(jī)制或者“微任務(wù)(micro - task)”機(jī)制來(lái)實(shí)現(xiàn)。

由于 promise 的實(shí)施代碼本身就是平臺(tái)代碼(譯者注:即都是 JavaScript),故代碼自身在處理在處理程序時(shí)可能已經(jīng)包含一個(gè)任務(wù)調(diào)度隊(duì)列。

調(diào)用要求

onFulfilled 和 onRejected 必須被作為函數(shù)調(diào)用(即沒(méi)有 this 值)

多次調(diào)用

then 方法可以被同一個(gè) promise 調(diào)用多次

當(dāng) promise 成功執(zhí)行時(shí),所有 onFulfilled 需按照其注冊(cè)順序依次回調(diào)

當(dāng) promise 被拒絕執(zhí)行時(shí),所有的 onRejected 需按照其注冊(cè)順序依次回調(diào)

簡(jiǎn)易版實(shí)踐
我們先通過(guò)實(shí)踐一個(gè)簡(jiǎn)易版的Promise來(lái)消化一下上面Promises/A+規(guī)范的基本要求。

首先

npm init 

// 測(cè)試實(shí)現(xiàn)是否符合 promises/A+ 規(guī)范

npm install promises-aplus-tests -D 

package.json

{
  "name": "ajpromise",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "promises-aplus-tests ./simple.js"
  },
  "author": "webfansplz",
  "license": "MIT",
  "devDependencies": {
    "promises-aplus-tests": "^2.1.2"
  }
}
    

simple.js

//Promise 的三種狀態(tài)  (滿足要求 -> Promise的狀態(tài))
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class AjPromise {
  constructor(fn) {
    //當(dāng)前狀態(tài)
    this.state = PENDING;
    //終值
    this.value = null;
    //拒因
    this.reason = null;
    //成功態(tài)回調(diào)隊(duì)列
    this.onFulfilledCallbacks = [];
    //拒絕態(tài)回調(diào)隊(duì)列
    this.onRejectedCallbacks = [];

    //成功態(tài)回調(diào)
    const resolve = value => {
      // 使用macro-task機(jī)制(setTimeout),確保onFulfilled異步執(zhí)行,且在 then 方法被調(diào)用的那一輪事件循環(huán)之后的新執(zhí)行棧中執(zhí)行。
      setTimeout(() => {
        if (this.state === PENDING) {
          // pending(等待態(tài))遷移至 fulfilled(執(zhí)行態(tài)),保證調(diào)用次數(shù)不超過(guò)一次。
          this.state = FULFILLED;
          // 終值
          this.value = value;
          this.onFulfilledCallbacks.map(cb => {
            this.value = cb(this.value);
          });
        }
      });
    };
    //拒絕態(tài)回調(diào)
    const reject = reason => {
      // 使用macro-task機(jī)制(setTimeout),確保onRejected異步執(zhí)行,且在 then 方法被調(diào)用的那一輪事件循環(huán)之后的新執(zhí)行棧中執(zhí)行。 (滿足要求 -> 調(diào)用時(shí)機(jī))
      setTimeout(() => {
        if (this.state === PENDING) {
          // pending(等待態(tài))遷移至 fulfilled(拒絕態(tài)),保證調(diào)用次數(shù)不超過(guò)一次。
          this.state = REJECTED;
          //拒因
          this.reason = reason;
          this.onRejectedCallbacks.map(cb => {
            this.reason = cb(this.reason);
          });
        }
      });
    };
    try {
      //執(zhí)行promise
      fn(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    typeof onFulfilled === "function" && this.onFulfilledCallbacks.push(onFulfilled);
    typeof onRejected === "function" && this.onRejectedCallbacks.push(onRejected);
    // 返回this支持then 方法可以被同一個(gè) promise 調(diào)用多次
    return this;
  }
}

就這樣,一個(gè)簡(jiǎn)單的promise就完成了.

new AjPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(2);
  }, 2000);
})
  .then(res => {
    console.log(res);
    return res + 1;
  })
  .then(res => {
    console.log(res);
  });

//output  

// delay 2s..
//  2 
//  3 

接下來(lái),我們來(lái)看看我們的實(shí)現(xiàn)是否完全符合promises/A+規(guī)范~

npm run test

GG,測(cè)試用例只過(guò)了一小部分,大部分飄紅~

OK,接下來(lái),我們來(lái)繼續(xù)了解promises/A+ 進(jìn)一步的規(guī)范要求~

進(jìn)一步要求

由于接下來(lái)的要求比較抽象和難理解,所以我們將一步一步實(shí)踐來(lái)加深理解。

1. 返回

1.then方法必須返回一個(gè)promise對(duì)象

2.如果 onFulfilled 或者 onRejected 返回一個(gè)值 x ,則運(yùn)行下面的 Promise 解決過(guò)程:[[Resolve]](promise2, x)

3.如果 onFulfilled 或者 onRejected 拋出一個(gè)異常 e ,則 promise2 必須拒絕執(zhí)行,并返回拒因 e。

4.如果 onFulfilled 不是函數(shù)且 promise1 成功執(zhí)行, promise2 必須成功執(zhí)行并返回相同的值。

5.如果 onRejected 不是函數(shù)且 promise1 拒絕執(zhí)行, promise2 必須拒絕執(zhí)行并返回相同的據(jù)因。

6.不論 promise1 被 reject 還是被 resolve 時(shí) promise2 都會(huì)被 resolve,只有出現(xiàn)異常時(shí)才會(huì)被 rejected。

我們通過(guò)以上要求來(lái)一步一步完善then方法
1.

// 1.首先,then方法必須返回一個(gè)promise對(duì)象
  then(onFulfilled, onRejected) {
    let newPromise;
    return (newPromise = new AjPromise((resolve, reject) => {}));
  }

2.

  then(onFulfilled, onRejected) {
    let newPromise;
    return (newPromise = new AjPromise((resolve, reject) => {
      // 2.如果 onFulfilled 或者 onRejected 返回一個(gè)值 x ,則運(yùn)行下面的 Promise 解決過(guò)程:[[Resolve]](promise2, x)
      this.onFulfilledCallbacks.push(value => {
        let x = onFulfilled(value);
        //解決過(guò)程 resolvePromise
        resolvePromise(newPromise, x);
      });
      this.onRejectedCallbacks.push(reason => {
        let x = onRejected(reason);
        //解決過(guò)程 resolvePromise
        resolvePromise(newPromise, x);
      });
    }));
  }
  // 解決過(guò)程
  function resolvePromise() {
  //...
  }

3.

  then(onFulfilled, onRejected) {
    let newPromise;
    return (newPromise = new AjPromise((resolve, reject) => {
      //  3.如果 onFulfilled 或者 onRejected 拋出一個(gè)異常 e ,則 promise2 必須拒絕執(zhí)行,并返回拒因 e。
      this.onFulfilledCallbacks.push(value => {
        try {
          let x = onFulfilled(value);
          resolvePromise(newPromise, x);
        } catch (e) {
          reject(e);
        }
      });
      this.onRejectedCallbacks.push(reason => {
        try {
          let x = onRejected(reason);
          resolvePromise(newPromise, x);
        } catch (e) {
          reject(e);
        }
      });
    }));
  }

4,5.

  then(onFulfilled, onRejected) {  
    let newPromise;
    // 4.如果 onFulfilled 不是函數(shù)且 promise1 成功執(zhí)行, promise2 必須成功執(zhí)行并返回相同的值。
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
    // 5.如果 onRejected 不是函數(shù)且 promise1 拒絕執(zhí)行, promise2 必須拒絕執(zhí)行并返回相同的據(jù)因。
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : reason => {
            throw reason;
          };
    return (newPromise = new AjPromise((resolve, reject) => {
      this.onFulfilledCallbacks.push(value => {
        try {
          let x = onFulfilled(value);
          resolvePromise(newPromise, x);
        } catch (e) {
          reject(e);
        }
      });
      this.onRejectedCallbacks.push(reason => {
        try {
          let x = onRejected(reason);
          resolvePromise(newPromise, x);
        } catch (e) {
          reject(e);
        }
      });
    }));
  }

6.

  then(onFulfilled, onRejected) {
    let newPromise;

    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : reason => {
            throw reason;
          };
    // 2.2.6規(guī)范 對(duì)于一個(gè)promise,它的then方法可以調(diào)用多次.
    // 當(dāng)在其他程序中多次調(diào)用同一個(gè)promise的then時(shí) 由于之前狀態(tài)已經(jīng)為FULFILLED / REJECTED狀態(tài),則會(huì)走以下邏輯,
    // 所以要確保為FULFILLED / REJECTED狀態(tài)后 也要異步執(zhí)行onFulfilled / onRejected ,這里使用setTimeout

    // 6.不論 promise1 被 reject 還是被 resolve 時(shí) promise2 都會(huì)被 resolve,只有出現(xiàn)異常時(shí)才會(huì)被 rejected。
    // 由于在接下來(lái)的解決過(guò)程中需要調(diào)用resolve,reject進(jìn)行處理,處理我們?cè)谡{(diào)用處理過(guò)程時(shí),傳入?yún)?shù)
    if (this.state == FULFILLED) {  
      return (newPromise = new AjPromise((resolve, reject) => {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }));
    }
    if (this.state == REJECTED) {
      return (newPromise = new AjPromise((resolve, reject) => {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }));
    }
    if (this.state === PENDING) {
      return (newPromise = new AjPromise((resolve, reject) => {
        this.onFulfilledCallbacks.push(value => {
          try {
            let x = onFulfilled(value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
        this.onRejectedCallbacks.push(reason => {
          try {
            let x = onRejected(reason);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }));
    }
  }

ok,完整的then方法搞定了。相信通過(guò)以上實(shí)踐,你對(duì)返回要求已經(jīng)有了更深的理解。

2. Promise 解決過(guò)程
Promise 解決過(guò)程是一個(gè)抽象的操作,其需輸入一個(gè) promise 和一個(gè)值,我們表示為 [[Resolve]](promise, x),如果 x 有 then 方法且看上去像一個(gè) Promise ,解決程序即嘗試使 promise 接受 x 的狀態(tài);否則其用 x 的值來(lái)執(zhí)行 promise 。  

這種 thenable 的特性使得 Promise 的實(shí)現(xiàn)更具有通用性:只要其暴露出一個(gè)遵循 Promise/A+ 協(xié)議的 then 方法即可;這同時(shí)也使遵循 Promise/A+ 規(guī)范的實(shí)現(xiàn)可以與那些不太規(guī)范但可用的實(shí)現(xiàn)能良好共存。

運(yùn)行 [[Resolve]](promise, x) 需遵循以下步驟:

1。x 與 promise 相等

如果 promise 和 x 指向同一對(duì)象,以 TypeError 為據(jù)因拒絕執(zhí)行 promise。

2。x 為 Promise

如果 x 為 Promise ,則使 promise 接受 x 的狀態(tài)。

如果 x 處于等待態(tài), promise 需保持為等待態(tài)直至 x 被執(zhí)行或拒絕。

如果 x 處于執(zhí)行態(tài),用相同的值執(zhí)行 promise。

如果 x 處于拒絕態(tài),用相同的據(jù)因拒絕 promise。

3。x 為對(duì)象或函數(shù)

如果 x 為對(duì)象或者函數(shù):

把 x.then 賦值給 then。

如果取 x.then 的值時(shí)拋出錯(cuò)誤 e ,則以 e 為據(jù)因拒絕 promise。

如果 then 是函數(shù),將 x 作為函數(shù)的作用域 this 調(diào)用之。傳遞兩個(gè)回調(diào)函數(shù)作為參數(shù),第一個(gè)參數(shù)叫做 resolvePromise ,第二個(gè)參數(shù)叫做 rejectPromise:

如果 resolvePromise 以值 y 為參數(shù)被調(diào)用,則運(yùn)行 [[Resolve]](promise, y)

如果 rejectPromise 以據(jù)因 r 為參數(shù)被調(diào)用,則以據(jù)因 r 拒絕 promise

如果 resolvePromise 和 rejectPromise 均被調(diào)用,或者被同一參數(shù)調(diào)用了多次,則優(yōu)先采用首次調(diào)用并忽略剩下的調(diào)用

如果調(diào)用 then 方法拋出了異常 e:

如果 resolvePromise 或 rejectPromise 已經(jīng)被調(diào)用,則忽略之

否則以 e 為據(jù)因拒絕 promise

如果 then 不是函數(shù),以 x 為參數(shù)執(zhí)行 promise

如果 x 不為對(duì)象或者函數(shù),以 x 為參數(shù)執(zhí)行 promise

如果一個(gè) promise 被一個(gè)循環(huán)的 thenable 鏈中的對(duì)象解決,而 [[Resolve]](promise, thenable) 的遞歸性質(zhì)又使得其被再次調(diào)用,根據(jù)上述的算法將會(huì)陷入無(wú)限遞歸之中。算法雖不強(qiáng)制要求,但也鼓勵(lì)施者檢測(cè)這樣的遞歸是否存在,若檢測(cè)到存在則以一個(gè)可識(shí)別的 TypeError 為據(jù)因來(lái)拒絕 promise 。

1.x 與 promise 相等

function resolvePromise(promise2, x, resolve, reject) {
  //x 與 promise 相等 
  //如果從onFulfilled中返回的x 就是promise2 就會(huì)導(dǎo)致循環(huán)引用報(bào)錯(cuò)
  
  //如果 promise 和 x 指向同一對(duì)象,以 TypeError 為據(jù)因拒絕執(zhí)行 promise
  if (x === promise2) {
    reject(new TypeError("循環(huán)引用"));
  }
}

2.x 為 Promise。

function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    reject(new TypeError("循環(huán)引用"));
  }
  // x 為 Promise
  else if (x instanceof AjPromise) {
    // 如果 x 為 Promise ,則使 promise 接受 x 的狀態(tài)
    // 如果 x 處于等待態(tài), promise 需保持為等待態(tài)直至 x 被執(zhí)行或拒絕
    if (x.state === PENDING) {
      x.then(
        y => {
          resolvePromise(promise2, y, resolve, reject);
        },
        reason => {
          reject(reason);
        }
      );
    } else {
      // 如果 x 處于執(zhí)行態(tài),用相同的值執(zhí)行 promise
      // 如果 x 處于拒絕態(tài),用相同的據(jù)因拒絕 promise
      x.then(resolve, reject);
    }
  }
}

3.x 為對(duì)象或函數(shù)

function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    reject(new TypeError("循環(huán)引用"));
  }
  if (x instanceof AjPromise) {
    if (x.state === PENDING) {
      x.then(
        y => {
          resolvePromise(promise2, y, resolve, reject);
        },
        reason => {
          reject(reason);
        }
      );
    } else {
      x.then(resolve, reject);
    }
  } else if (x && (typeof x === "function" || typeof x === "object")) {
    // 避免多次調(diào)用
    let called = false;
    try {
      //把 x.then 賦值給 then
      let then = x.then;
      if (typeof then === "function") {
        // 如果 then 是函數(shù),將 x 作為函數(shù)的作用域 this 調(diào)用之。
        // 傳遞兩個(gè)回調(diào)函數(shù)作為參數(shù),第一個(gè)參數(shù)叫做 resolvePromise ,第二個(gè)參數(shù)叫做 rejectPromise
        // 如果 resolvePromise 和 rejectPromise 均被調(diào)用,或者被同一參數(shù)調(diào)用了多次,則優(yōu)先采用首次調(diào)用并忽略剩下的調(diào)用
        then.call(
          x,
          // 如果 resolvePromise 以值 y 為參數(shù)被調(diào)用,則運(yùn)行[[Resolve]](promise, y)
          y => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          // 如果 rejectPromise 以據(jù)因 r 為參數(shù)被調(diào)用,則以據(jù)因 r 拒絕 promise
          r => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      }else {
        // 如果 then 不是函數(shù),以 x 為參數(shù)執(zhí)行 promise
        resolve(x);
      }  
    } catch (e) {
      // 如果取 x.then 的值時(shí)拋出錯(cuò)誤 e ,則以 e 為據(jù)因拒絕 promise
      // 如果調(diào)用 then 方法拋出了異常 e:
      // 如果 resolvePromise 或 rejectPromise 已經(jīng)被調(diào)用,則忽略之
      // 否則以 e 為據(jù)因拒絕 promise
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    // 如果 x 不為對(duì)象或者函數(shù),以 x 為參數(shù)執(zhí)行 promise
    resolve(x);
  }
}

Ok~比較復(fù)雜的解決過(guò)程也讓我們搞定了.接下來(lái)我們整合下代碼

Promises/A+ 規(guī)范 實(shí)踐
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class AjPromise {
  constructor(fn) {
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = value => {
      if (value instanceof Promise) {
        return value.then(resolve, reject);
      }
      setTimeout(() => {
        if (this.state === PENDING) {
          this.state = FULFILLED;
          this.value = value;
          this.onFulfilledCallbacks.map(cb => {
            cb = cb(this.value);
          });
        }
      });
    };
    const reject = reason => {
      setTimeout(() => {
        if (this.state === PENDING) {
          this.state = REJECTED;
          this.reason = reason;
          this.onRejectedCallbacks.map(cb => {
            cb = cb(this.reason);
          });
        }
      });
    };
    try {
      fn(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    let newPromise;

    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : reason => {
            throw reason;
          };
    if (this.state === FULFILLED) {
      return (newPromise = new AjPromise((resolve, reject) => {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }));
    }
    if (this.state === REJECTED) {
      return (newPromise = new AjPromise((resolve, reject) => {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }));
    }
    if (this.state === PENDING) {
      return (newPromise = new AjPromise((resolve, reject) => {
        this.onFulfilledCallbacks.push(value => {
          try {
            let x = onFulfilled(value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
        this.onRejectedCallbacks.push(reason => {
          try {
            let x = onRejected(reason);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }));
    }
  }
}
function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    reject(new TypeError("循環(huán)引用"));
  }
  if (x instanceof AjPromise) {
    if (x.state === PENDING) {
      x.then(
        y => {
          resolvePromise(promise2, y, resolve, reject);
        },
        reason => {
          reject(reason);
        }
      );
    } else {
      x.then(resolve, reject);
    }
  } else if (x && (typeof x === "function" || typeof x === "object")) {
    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);
          },
          r => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

AjPromise.deferred = function() {
  let defer = {};
  defer.promise = new AjPromise((resolve, reject) => {
    defer.resolve = resolve;
    defer.reject = reject;
  });
  return defer;
};

module.exports = AjPromise;

再來(lái)看看我們的實(shí)現(xiàn)是否符合Promises/A+規(guī)范

npm run test

nice,測(cè)試用例全部通過(guò)!

源碼地址

傳送門(mén)

如果覺(jué)得有幫助到你,請(qǐng)給個(gè)star支持下作者~

參考文獻(xiàn)

Promises/A+規(guī)范譯文

Promise詳解與實(shí)現(xiàn)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101153.html

相關(guān)文章

  • JavaScript 異步

    摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫(xiě)一個(gè)符合規(guī)范并可配合使用的寫(xiě)一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開(kāi)發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...

    tuniutech 評(píng)論0 收藏0
  • Koa / Co / Bluebird or Q / Generators / Promises /

    摘要:經(jīng)常游蕩在的我總能發(fā)現(xiàn)許多好問(wèn)題和好答案。盡管網(wǎng)絡(luò)上有著各式各樣的關(guān)于該主題的指導(dǎo),但涉及到在各種情景下的最佳實(shí)踐,或者較好實(shí)踐的方面還是不夠清晰。我寄希望于針對(duì)我這篇裹腳布式問(wèn)題的回復(fù)可以改變這一現(xiàn)狀。我感覺(jué)因此收益的絕對(duì)不止是我一個(gè)人。 經(jīng)常游蕩在 SO 的我總能發(fā)現(xiàn)許多好問(wèn)題和好答案。它們的好不僅僅在于知識(shí)的價(jià)值,更可貴之處在于如何表達(dá):如何提問(wèn)/如何回答。不久前我在 SF...

    xingpingz 評(píng)論0 收藏0
  • ES6-7

    摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書(shū)了入門(mén),覺(jué)得看看這本書(shū)就足夠了。前端的異步解決方案之和異步編程模式在前端開(kāi)發(fā)過(guò)程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(shū)(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書(shū)的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評(píng)論0 收藏0
  • Promises A+規(guī)范原文解讀 + es6實(shí)現(xiàn)(附詳細(xì)注釋)

    摘要:英文官方文檔原文前言寫(xiě)本文的目的,是為了更好的理解,通過(guò)解讀翻譯原文,逐行解析原文通過(guò)代碼一行一行實(shí)現(xiàn)。英中原因是一個(gè)值結(jié)果表明被拒絕的原因。英中在法律允許的范圍內(nèi),組織已放棄所有版權(quán)及規(guī)范的相關(guān)或相鄰權(quán)利。 英文官方文檔原文:https://promisesaplus.com/ 前言 寫(xiě)本文的目的,是為了更好的理解promise,通過(guò)解讀翻譯原文,逐行解析原文通過(guò)代碼一行一行實(shí)現(xiàn)。...

    v1 評(píng)論0 收藏0
  • 理解 Promise 的工作原理

    摘要:前兩個(gè)函數(shù)對(duì)應(yīng)的兩種狀態(tài)和的回調(diào)函數(shù)。返回值是和對(duì)應(yīng)的方法,但是會(huì)在下一事件循環(huán)返回。此外,在規(guī)范中,由方法生成的對(duì)象是已執(zhí)行還是已拒絕,取決于由方法調(diào)用的那個(gè)回調(diào)是返回值還是拋出錯(cuò)誤。但是對(duì)于其工作原理卻有些懵懂和好奇。 原文: https://blog.coding.net/blog/how-do-promises-work Javascript 采用回調(diào)函數(shù)(callback)來(lái)...

    Achilles 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

hqman

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<