ES6 - 手寫Promise及Promise原理解析(一) => 關於Promise的狀態管理

在ES6給我們提供的衆多新特性中, Promise一定是最好用最出色的API之一, 筆者也一直想試試寫一個自己的Promise, so let’s go!

這篇博客僅寫狀態管理, 總共分四篇博客寫完

1. Promise對於狀態的控制

從構造函數開始解析Promise

const promise = new Promise((resolve, reject) => {
    console.log('我會立即執行'); 
})

console.log(promise);

上面是官方原版的Promise, 我們來看看控制檯輸出了啥

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-cn3JkWNF-1587650994378)(./Promise實例輸出.png)]

通過這種輸出, 我們基本可以確定一些事情來方便我們手寫Promise

1. Promise是一個構造函數, 且接受一個函數作爲參數, 他構造出的實例一開始具有兩個屬性,
 一個用來表示當前狀態, 一個用來表示Promise結果

2. 寫在函數參數中的代碼會立即執行, 同時函數參數會被傳遞兩個參數, 
一個resolve, 一個reject用於處理不同的情況

OK, 根據上面兩點, 我們來寫一個初步的Promise, 一步一步來嘛

1. Promise是一個構造函數, 且接受一個函數作爲參數, 他構造出的實例一開始具有兩個屬性, 一個用來表示當前狀態, 一個用來表示Promise結果

每個實例都有這兩個屬性, 代表我們要麼寫在原型上, 要麼this上, 而這兩個屬性很明顯不是繼承的, 而是出生就附着的, 所以肯定寫在this上

//  立即執行函數封閉作用域
const MyPromise = (function() {

    // 當前promise狀態, 由於我們寫不了雙中括號,所以用Symbol代替了
    const PromiseStatus = Symbol('PromiseStatus');
    const PromiseValue = Symbol('PromiseValue');
    // 立即執行函數執行 完畢以後返回一個class類給外部的MyPromise變量
    return class MyPromise {
        /**
         * 
         * @param {未決(pedding)狀態下的執行函數, 
         * 也就是別人傳進來的函數參數} executor 
         */
        constructor(executor) {
            
            // 書寫在this上的兩個屬性, 狀態一開始爲pedding
            // Promise結果一開始爲undefined
            this[PromiseStatus] = 'pedding';
            this[PromiseValue] = undefined;
    
        }
    }
}())

寫到這, 我們看看自己寫的Promise效果吧

// 查看自己寫的Promise效果
const myPromise = new MyPromise((resolve, reject) => {

            
        })
console.log(myPromise)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zGPAFGtg-1587650994381)(./初始化Promise狀態.png)]

基本上兩個屬性都有了, 繼續走

2. 寫在函數參數中的代碼會立即執行, 同時函數參數會被傳遞兩個參數, 一個resolve, 一個reject用於處理不同的情況


const MyPromise = (function() {
    const PromiseStatus = Symbol('PromiseStatus');
    const PromiseValue = Symbol('PromiseValue');
    
    // Promise的三種狀態
    const _PEDDING = 'pedding';
    const _RESOLVE = 'resolved';
    const _REJECT = 'rejected';

    // 改變狀態的方法
    const ChangePromiseStatus = Symbol('ChangePromiseStatus');

       
    // 要拿self來接管this指向, 否則出問題
    let self = null;

    // resolve和reject方法, resolve會將data傳遞過去,
    // reject會將error搞過去

    // resolve一旦觸發, 整個Promise實例狀態將變更爲resolved, 且不可逆

    const resolve = function(_data) {
        self[ChangePromiseStatus](_RESOLVE, _data);
    };

    // reject一旦觸發, 整個Promise實例狀態將變更爲rejected, 不可逆
    const reject = (_error) => {
        self[ChangePromiseStatus](_REJECT, _error);

    }

    return class MyPromise {
        // 修改Promise狀態的方法
        [ChangePromiseStatus](status, result) {
            // 我們知道如果promise狀態不是pedding的話, 就是不可逆的
            // 所以我們這裏要做一下短路
            if(this[PromiseStatus] !== _PEDDING) return;
            // 如果是pedding狀態, 則我們更改狀態也更改值
            this[PromiseStatus] = status;
            this[PromiseValue] = result;
        }

        constructor(executor) {
            self = this;
            this[PromiseStatus] = _PEDDING;
            this[PromiseValue] = undefined;
            // 2. construtor是類只要一被實例化馬上就會被執行的一個方法
            // 所以我們是不是可以在這裏面直接執行以下executor

            // 同時excutor執行的時候要傳遞兩個函數進去, 一個resolve, 一個reject
            // 還有就是要注意的一點: 如果在executor中直接報錯了, 那麼會走進reject
            // 所以我們需要捕獲一下錯誤吧
            try {
                executor(resolve, reject);
            }catch(error) {
                // 一旦報錯, 送進reject方法執行
               reject(error);
            }
            
        }
    }
}())

來試試看


const myPromise = new MyPromise((resolve, reject) => {
    console.log('helleWorld');
    console.log(age);
})

console.log(myPromise)

我們會看到控制檯如下

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NRqpt7RT-1587650994383)(./executor執行.png)]

這個時候我們傳遞進去的函數參數就被立即走掉了, 並且報了錯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章