Promise的使用和實現

Promise的使用和特點

  • Promise是一個構造函數,接收一個函數(executor)作為參數,這個函數的參數有兩個,resolve,reject
  • executor是立即執(zhí)行函數,也就是在new Promise的時候,在Promise構造函數中直接被調用的
  • resolve, 是內部創(chuàng)建的函數,用戶調用該函數可以讓promise變成成功態(tài)(fufilled)
  • reject,是內部創(chuàng)建的函數,用戶調用該函數可以讓promise變成失敗態(tài)(rejected)
  • promise有三種狀態(tài),默認是padding(等待態(tài))、成功態(tài)(fufilled)、失敗態(tài)(rejected)
  • 狀態(tài)不可逆,一旦成功就不能失敗,一旦失敗就不能成功
  • 常用的then方法
    • 是原型方法
    • then方法調用接收兩個參數作為參數,1. onFulfilled / 2. onRejected
    • then方法支持鏈式調用,可以一直.then().then()....
    • then方法的兩個參數onFulfilled和onRejected的返回值,會作為下一次then的結果,如果返回值是一個promise,會解析這個promise,將promise的結果作為下一次then的結果
// 1. 創(chuàng)建promise實例
const p = new Promise((resolve, reject) => {
   // 直接執(zhí)行的邏輯...
})
p.then(res => {
  return 100
  return new Promise((resolve, reject) => { resolve('hello') })
}).then(res => {
  console.log(res) // 100  / 'hello'
})

Promise A+ 規(guī)范,實現符合規(guī)范的promise

實現流程:
  1. Promise是一個構造函數,參數是一個executor函數
  2. executor的參數是resove和reject
  3. promise的三個狀態(tài),狀態(tài)不可逆
  4. promise的兩個值:1. 成功的value 2. 失敗的原因reason
  5. executor中邏輯異步的處理,使用發(fā)布訂閱的模式處理異步
  6. then方法中兩個參數onFulfilled和onRejected的返回值的處理,使用resolvePromise來遞歸解析promise
實現代碼:
class Promise {
    constructor(executor) {
        // promise 的三個狀態(tài) padding fulfilled rejected
        this.value = null;
        this.reason = null;
        this.fulfilledCbs = []; // 成功回調
        this.rejectedCbs = [];
        this.status = 'padding'

        const resolve = (value) => {
            if (this.status === 'padding') {
                this.status = 'fulfilled';
                this.value = value
                for (let i = 0; i < this.fulfilledCbs.length; i++) {
                    const fn = this.fulfilledCbs[i];
                    fn()
                }
            }
        }

        const reject = (reason) => {
            if (this.status === 'padding') {
                this.status = 'rejected'
                this.reason = reason
                for (let i = 0; i < this.rejectedCbs.length; i++) {
                    const fn = this.rejectedCbs[i];
                    fn()
                }
            }
        }

        try {
            executor(resolve, reject)
        } catch (e) {
            reject(e)
        }
    }

    // then 方法返回一個新的promise,叫promsie2
    // then 方法中的回調函數返回值可以是普通值或者promsie,如果是promise,會解析promise的值作為下一次then的值
    then(onFulfilled, onRejected) {
        const isFunction = val => typeof val === 'function';
        onFulfilled = isFunction(onFulfilled) ? onFulfilled : (value) => value; // 將then的結果透傳給下一次then
        onRejected = isFunction(onRejected) ? onRejected : (error) => {
            throw error
        }

        let promise2; // then方法返回的promise叫promise2
        if (this.status === 'padding') { // 說明executor中的邏輯是異步執(zhí)行的
            promise2 = new Promise((resolve, reject) => {
                this.fulfilledCbs.push(() => {
                    setTimeout(() => {
                        try {
                            // then方法回調的返回值叫做x
                            const x = onFulfilled(this.value)
                            resovlePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0);
                })

                this.rejectedCbs.push(() => {
                    setTimeout(() => {
                        try {
                            // then方法回調的返回值叫做x
                            const x = onRejected(this.reason)
                            resovlePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0);
                })
            })
        } else if (this.status === 'fulfilled') {
            promise2 = new Promise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        // then方法回調的返回值叫做x
                        const x = onFulfilled(this.value)
                        resovlePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0);
            })

        } else if (this.status === 'rejected') {
            promise2 = new Promise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        // then方法回調的返回值叫做x
                        const x = onRejected(this.reason)
                        resovlePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0);
            })
        }
        return promise2;
    }
}

function resovlePromise(promise2, x, resolve, reject) {
    // 返回的x可能是一個promise,但是一定不能和promise2相同
    if (promise2 === x) {
        return reject(new TypeError("same promise"));
    }

    // 分析x的值,可能是一個普通的值,可能是一個promise

    // 1. 如果 x 是一個 promise,使用它的狀態(tài)
    if (x instanceof Promise) {
        x.then(val => {
            // y有可能也是一個promise,遞歸解析
            resovlePromise(promise2, val, resolve, reject)
        }, reject)
    }

    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        try {
            let then = x.then;
            let flag = false;
            if (typeof then === 'function') {
                try {
                    // x 作為this調用then
                    then.call(x, y => {
                        if (!flag) {
                            resovlePromise(promise2, y, resolve, reject)
                            flag = true;
                        }
                    }, r => {
                        if (!flag) {
                            reject(r)
                            flag = true;
                        }
                    })
                } catch (e) {
                    if (!flag) {
                        reject(e)
                        flag = true;
                    }
                }
            } else {
                resolve(x)
            }
        } catch (e) {
            reject(e)
        }

    } else {
        resolve(x)
    }
}
測試promise
  1. 增加測試代碼
Promise.deferred = function () {
    let def = {};
    def.promise = new Promise(function (resolve, reject) {
        def.resolve = resolve;
        def.reject = reject;
    });
    return def;
}
module.exports = Promise
  1. 安裝測試包
npm install -g promises-aplus-tests 
promises-aplus-tests  promise.js
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容