你也能夠手寫本身的Promise(一)

我寫這篇文章不打算介紹Promise產生的緣由以及它解決的問題,我只是想寫一篇關於實現本身Promise的文章。若是代碼以及邏輯有什麼不對的地方,請你們指出來。就這些,開始正題。數組

前提:咱們要知道Promise是基於Promises/A+規範的。其中好多變量和方法名都是從這裏來的。 咱們先從Promise的使用開始,寫幾個測試例子。promise

let promise = new Promise((resolve, reject) =>{
    // console.log("1");
    // resolve("成功");
    // reject("失敗");
    // console.log("2");// 第一步


    // reject("失敗");
    // resolve("成功");// 第二步

    // setTimeout(() => {
    //     resolve("success");
    // }, 2000);

    throw new Error("手動拋出錯誤");// 第四步
});
promise.then((value) => {
    console.log("then第一個方法:"+value);
}, (err) => {
    console.log("then第二個方法:"+err);
})
promise.then((value) => {
    console.log("then第一個方法:"+value);
}, (err) => {
    console.log("then第二個方法:"+err);
})
console.log("3");
複製代碼

第一步輸出緩存

  • 1
  • 2
  • 3
  • then第一個方法:成功
  • then第一個方法:成功

第二步輸出bash

  • 3
  • then第二個方法:失敗
  • then第二個方法:失敗

第三步輸出異步

  • 3 兩秒以後
  • then第一個方法:success
  • then第一個方法:success

第四步輸出函數

  • 3
  • then第二個方法:Error: 手動拋出錯誤
  • then第二個方法:Error: 手動拋出錯誤

最後輸出「成功」說明 then是異步執行的測試

根據以上幾個例子咱們能夠推出如下幾點內容:ui

  • Promise是一個構造函數(使用了 new)
  • Promise接收一個參數,而且這個參數是一個函數(爲了方便描述,咱們稱之爲 executor)
  • executor在 new Promise時執行
  • new Promise中能夠支持異步行爲(第三步)
  • executor有兩個參數(resolve,reject)
  • resolve和reject不會咱們傳進去的,說明是屬於Promise內容提供的
  • resolve和reject都是函數,而且都接收一個參數。看規範:resolve接收參數稱之爲value,reject接收參數稱之爲reason
  • 每一個Promise實例上都有then方法
  • then方法是異步的
  • then方法中有兩個參數onFulfilled和onRejected 分別是成功的回調(執行resolve)和失敗的回調(執行reject)。看這裏
  • 一個Promise中resolve和reject只會執行一個,規範中有提到 Promise States,你們能夠看下
  • 同一個promise的實例能夠then屢次,成功時回調用全部的成功方法,失敗時回調用全部的失敗方法
  • 若是發現錯誤就會走入失敗態

這麼一大坨東西,看着有點亂。咱們就根據咱們得出的結論開始寫屬於本身的Promise。寫的過程當中思路慢慢就清晰了。this

let myPromise = function (executor) {
    let self = this;//緩存一下this

    self.status = 'pending';// 狀態管理 狀態的變化只能由pending變爲resolved或者rejected。一件事情不能既成功又失敗。因此resolved和rejected不能相互轉化。
    self.value = undefined;// 成功後的值 傳給resolve
    self.reason = undefined;//失敗緣由 傳給reject

    self.onResolvedCallbacks = [];// 存放then中成功的回調
    self.onRejectedCallbacks = []; // 存放then中失敗的回調 
    // 這裏說明一下,第三步使用定時器。執行完 new Promise 以後,會執行then方法,此時會把then中的方法緩存起來,並不執行:此時狀態仍是pending。等到定時器2秒以後,執行
    // resolve|reject 時,而是依次執行存放在數組中的方法。 參考發佈訂閱模式

    function resolve(value) {
        // pending => resolved
        if (self.status === 'pending') {
            self.value = value;
            self.status = 'resolved';
            // 依次執行緩存的成功的回調
            self.onResolvedCallbacks.forEach(fn => fn(self.value));
        }
    }

    function reject(reason) {
        // pending => rejected
        if (self.status === 'pending') {
            self.value = value;
            self.status = 'rejected';
            // 依次執行緩存的失敗的回調
            self.onRejectedCallbacks.forEach(fn => fn(self.reason));
        }
    }

    try {
        //new Promise 時 executor執行
        executor(resolve, reject);
    } catch (error) {
        reject(error);// 當executor中執行有異常時,直接執行reject
    }
}

// 每一個Promise實例上都有then方法
Promise.prototype.then = function (onFulfilled, onRejected) {
    let self = this;

    // 執行了 resolve
    if (self.status === 'resolved') {
        // 執行成功的回調
        onFulfilled(self.value);
    }

    // 執行了 reject
    if (self.status === 'rejected') {
        // 執行失敗的回調
        onRejected(self.reason);
    }

    // new Promise中能夠支持異步行爲 當既不執行resolve又不執行reject時 狀態是默認的等待態pending
    if (self.status === 'pending') {
        // 緩存成功的回調
        self.onResolvedCallbacks.push(onFulfilled);
        // 緩存失敗的回調
        self.onRejectedCallbacks.push(onRejected);
    }
};
複製代碼

說明一下:這是最簡版,由於Promise的強大之處是鏈式調用。咱們這個只是雛形,因爲時間關係。咱們先到這裏。下一次咱們基於這個雛形實現符合Promises/A+規範的完整版。spa

第一次發表文章,但願各位大蝦多多支持。

相關文章
相關標籤/搜索