手寫Promise - 實例方法catch、finally

手寫Promise - 實現一個基礎的Promise
手寫Promise - 實例方法catch、finally
手寫Promise - 經常使用靜態方法all、any、resolve、reject、racejavascript

上一篇文章手寫了一個基礎的Promise,咱們繼續來完善它,爲其添加常常用到的catch和finally方法java

catch & finally

catch() 方法返回一個Promise,而且處理拒絕的狀況。咱們知道then方法的第二個參數其實就是幹這個用的,catch只是一個別名。segmentfault

finally() 方法返回一個Promise。在promise結束時,不管結果是fulfilled或者是rejected,都會執行指定的回調函數。和catch同樣,也只是對then的一個簡寫,至關因而傳入的函數既是onFulfilled也是onRejected。數組

有一點須要注意,finally和catch方法只是then的一個別名,實際上返回的仍是一個promise,徹底能夠這樣寫:promise.then().finally().then().catch().then()promise

咱們把上一章節的代碼拷過來,而後向裏面添加catch和finally方法。函數

class WPromise {
    static pending = 'pending';
    static fulfilled = 'fulfilled';
    static rejected = 'rejected';

    constructor(executor) {
        this.status = WPromise.pending; // 初始化狀態爲pending
        this.value = undefined; // 存儲 this._resolve 即操做成功 返回的值
        this.reason = undefined; // 存儲 this._reject 即操做失敗 返回的值
        // 存儲then中傳入的參數
        // 至於爲何是數組呢?由於同一個Promise的then方法能夠調用屢次
        this.callbacks = [];
        executor(this._resolve.bind(this), this._reject.bind(this));
    }

    // onFulfilled 是成功時執行的函數
    // onRejected 是失敗時執行的函數
    then(onFulfilled, onRejected) {
        // 返回一個新的Promise
        return new WPromise((nextResolve, nextReject) => {
            // 這裏之因此把下一個Promsie的resolve函數和reject函數也存在callback中
            // 是爲了將onFulfilled的執行結果經過nextResolve傳入到下一個Promise做爲它的value值
            this._handler({
                nextResolve,
                nextReject,
                onFulfilled,
                onRejected
            });
        });
    }

    // catch方法只有一個參數用於處理錯誤的狀況
    catch(onRejected) {
        return this.then(null, onRejected);
    }

    finally(onFinally) {
        return this.then(onFinally, onFinally);
    }

    _resolve(value) {
        // 處理onFulfilled執行結果是一個Promise時的狀況
        // 這裏可能理解起來有點困難
        // 當value instanof WPromise時,說明當前Promise確定不會是第一個Promise
        // 而是後續then方法返回的Promise(第二個Promise)
        // 咱們要獲取的是value中的value值(有點繞,value是個promise時,那麼內部存有個value的變量)
        // 怎樣將value的value值獲取到呢,能夠將傳遞一個函數做爲value.then的onFulfilled參數
        // 那麼在value的內部則會執行這個函數,咱們只須要將當前Promise的value值賦值爲value的value便可
        if (value instanceof WPromise) {
            value.then(
                this._resolve.bind(this),
                this._reject.bind(this)
            );
            return;
        }

        this.value = value;
        this.status = WPromise.fulfilled; // 將狀態設置爲成功

        // 通知事件執行
        this.callbacks.forEach(cb => this._handler(cb));
    }

    _reject(reason) {
        if (reason instanceof WPromise) {
            reason.then(
                this._resolve.bind(this),
                this._reject.bind(this)
            );
            return;
        }

        this.reason = reason;
        this.status = WPromise.rejected; // 將狀態設置爲失敗

        this.callbacks.forEach(cb => this._handler(cb));
    }

    _handler(callback) {
        const {
            onFulfilled,
            onRejected,
            nextResolve,
            nextReject
        } = callback;

        if (this.status === WPromise.pending) {
            this.callbacks.push(callback);
            return;
        }

        if (this.status === WPromise.fulfilled) {
            // 傳入存儲的值
            // 未傳入onFulfilled時,將undefined傳入
            const nextValue = onFulfilled
                ? onFulfilled(this.value)
                : undefined;
            nextResolve(nextValue);
            return;
        }

        if (this.status === WPromise.rejected) {
            // 傳入存儲的錯誤信息
            // 一樣的處理
            const nextReason = onRejected
                ? onRejected(this.reason)
                : undefined;
            nextReject(nextReason);
        }
    }
}

是的,就是這麼簡單,如今來測試一下:測試

function fetchData() {
    return new WPromise((resolve, reject) => {
        setTimeout(() => {
            reject(1);
        }, 1000);
    });
}

fetchData().finally((data) => {
    return data + 10;
}).finally((data) => {
    return new WPromise((resolve, reject) => {
        reject(data + 10);
    });
}).finally((data) => {
    console.log(data); // 21
})

以上就是catch和finally的模擬實現,若是理解了then的工做原理的話,理解catch和finally也沒啥問題。fetch

相關文章
相關標籤/搜索