promise由淺入深

小兔子發表於2018-03-19

前言

  • Promise 是非同步程式設計的一種解決方案,比傳統的解決方案——回撥函式和事件——更合理和更強大。它由社群最早提出和實現,ES6將其寫進了語言標準,統一了用法,原生提供Promise物件。
  • 所謂Promise,簡單說就是一個容器,裡面儲存著某個未來才會結束的事件(通常是一個非同步操作)的結果。從語法上說,Promise 是一個物件,從它可以獲取非同步操作的訊息。Promise 提供統一的 API,各種非同步操作都可以用同樣的方法進行處理。

promise 的特點

promise基本使用

const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 非同步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});
複製程式碼

術語

  • promise 一個帶有then方法的物件或者function
  • thenable 定義一個then方法的物件或者function
  • exception 是一個使用丟擲語句丟擲的值
  • reason promise被拒絕的原因

必備條件

1.promise的狀態

promise必須處在三個狀態之一: pending, fulfilled, or rejected。
複製程式碼
  • pending(進行中)
    • pending可以轉變成fulfilled或者rejected
  • fulfilled(已成功)
    • 如果是已成功狀態後,狀態不可再做修改
    • 並且有一個不可改變的value值
  • reject (已失敗)
    • 如果是已失敗狀態後,狀態不可再做修改
    • 並且有一個不可改變的reason

程式碼實現如下

function Promise(executor) { // executor是一個執行函式
    let self = this;
    self.status = 'pending';
    self.value = undefined; // 預設成功的值
    self.reason = undefined; // 預設失敗的原因
    self.onResolvedCallbacks = []; // 存放then成功的回撥
    self.onRejectedCallbacks = []; // 存放then失敗的回撥
    function resolve(value) { // 成功狀態
        if (self.status === 'pending') {
            self.status = 'resolved';
            self.value = value;
            self.onResolvedCallbacks.forEach(function (fn) {
                fn();
            });
        }
    }
    function reject(reason) { // 失敗狀態
        if (self.status === 'pending') {
            self.status = 'rejected';
            self.reason = reason;
            self.onRejectedCallbacks.forEach(function (fn) {
                fn();
            })
        }
    }
    try {
        executor(resolve, reject)
    } catch (e) { // 捕獲的時候發生異常,就直接失敗了
        reject(e);
    }
}
複製程式碼

2.then方法

  • promise必須提供一個then方法訪問當前的value或者reason
  • promise的then方法接受兩個引數
    • promise.then(onFulfilled, onRejected)
  1. onFulfilled和onRejected是兩個可選引數
    • 如果這兩個可選引數不是一個function,則必須被忽略
  2. 如果onFulfilled是一個function
    • 則他必須在promise是fulfiled狀態下被呼叫,並且攜帶promise的value作為第一個引數
    • 該方法不能在promise是fulfiled狀態前執行
    • 該方法可以被多次呼叫
  3. 如果onRejected是一個function
    • 則他必須在promise是rejected狀態下被呼叫,並且攜帶promise的reason作為第一個引數
    • 該方法不能在promise是rejected狀態前被執行
    • 該方法可以被多次呼叫
  4. 在同一個promise中,then方法有可能被多次呼叫
  5. then方法必須返回一個promise

3.promise的處理過程

  • promis的處理過程是我們通過[[Resolve]](promise, x)傳入 一個promise或者一個value的一個抽象的處理過程
  • 如果x是一個thenable,它試圖使承諾採用x的狀態,假設x表現至少有點像一個promise。否則,它履行promise與x的值。
  • 只要他們公開promiseA+-相容的方法,那麼就可以處理thenables允許promiseA+實現互動操作。
程式碼實現如下:

function resolvePromise(promise2, x, resolve, reject) {
    // 有可能這裡返回的x是別人的promise
    // 儘可能允許其他亂寫
    if (promise2 === x) { //這裡應該報一個型別錯誤,有問題
        return reject(new TypeError('迴圈引用了'))
    }
    // 看x是不是一個promise,promise應該是一個物件
    let called; // 表示是否呼叫過成功或者失敗
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        // 可能是promise {},看這個物件中是否有then方法,如果有then我就認為他是promise了
        try { // {then:1}
            let then = x.then;
            if (typeof then === 'function') {
                // 成功
                then.call(x, function (y) {
                    if (called) return
                    called = true
                    // y可能還是一個promise,在去解析直到返回的是一個普通值
                    resolvePromise(promise2, y, resolve, reject)
                }, function (err) { //失敗
                    if (called) return
                    called = true
                    reject(err);
                })
            } else {
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true;
            reject(e);
        }
    } else { // 說明是一個普通值1
        resolve(x); // 表示成功了
    }
}

Promise.prototype.then = function (onFulfilled, onRjected) {
    //成功和失敗預設不穿給一個函式
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
        return value;
    }
    onRjected = typeof onRjected === 'function' ? onRjected : function (err) {
        throw err;
    }
    let self = this;
    let promise2; //返回的promise
    if (self.status === 'resolved') {
        promise2 = new Promise(function (resolve, reject) {
            // 當成功或者失敗執行時有異常那麼返回的promise應該處於失敗狀態
            // x可能是一個promise 也有可能是一個普通的值
            setTimeout(function () {
                try {
                    let x = onFulfilled(self.value);
                    // x可能是別人promise,寫一個方法統一處理
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            })
        })
    }
    if (self.status === 'rejected') {
        promise2 = new Promise(function (resolve, reject) {
            setTimeout(function () {
                try {
                    let x = onRjected(self.reason);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            })

        })
    }
    // 當呼叫then時可能沒成功 也沒失敗
    if (self.status === 'pending') {
        promise2 = new Promise(function (resolve, reject) {
            // 此時沒有resolve 也沒有reject
            self.onResolvedCallbacks.push(function () {
                setTimeout(function () {
                    try {
                        let x = onFulfilled(self.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                })
            });
            self.onRejectedCallbacks.push(function () {
                setTimeout(function () {
                    try {
                        let x = onRjected(self.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            });
        })
    }
    return promise2;
}
複製程式碼

參考網站:

promisesaplus.com/

es6.ruanyifeng.com/

相關文章