【日常记录总结】手写实现简单的Promise

125 阅读4分钟

实现如下功能:

  1. .then()异步方法。
  2. .then()链式调用。

首先需要知道promise的三个状态,pending(等待),fulfilled(成功),rejected(失败),因此我们需要定义promise的三个状态。同时,我们需要处理成功的方法_resolve()和处理失败的方法_reject(),以及他们返回的内容value和error。因为.then()是异步的,我们还需要定义一个then()的方法来接收回调函数并把他们储存起来,以便在_resolve()和_reject()时调用。

基于以上要实现的功能,我们可以简单定义下promise方法:

class MyPromise {
    // promise 定义三个状态 等待 成功 失败
    static pending = "pending";
    static fulfilled = "fulfilled";
    static rejected = "rejected";

    constructor(executor) {
        // 默认等待状态
        this.status = MyPromise.pending; // 初始化状态为pending
        this.value = undefined; // 存储 this._resolve 即操作成功 返回的值
        this.error = undefined; // 存储 this._reject 即操作失败 返回的值
        // 存储then中传入的参数
        // callbacks是数组的原因是同一个Promise的then方法可以调用多次
        this.callbacks = [];
        //确定this的指向,防止this指向混乱
        executor(this._resolve.bind(this), this._reject.bind(this));
    }

    // 接收两个参数
    // onFulfilled 是成功时执行的函数
    // onRejected 是失败时执行的函数
    then(onFulfilled, onRejected) {
        // 这里可以理解为在注册事件
        // 也就是将需要执行的回调函数存储起来
        // 这两个函数 会在_resolve和_reject中调用
            this.callbacks.push({
                onFulfilled,
                onRejected,
            });
    }

    _resolve(value) {
        this.value = value;
        this.status = MyPromise.fulfilled; // 将状态设置为成功

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

    _reject(reason) {
        this.reason = reason;
        this.status = MyPromise.rejected; // 将状态设置为失败

        //cb 为callback简写
        this.callbacks.forEach((cb) => this._handler(cb));
    }

    _handler(callback) {
        const { onFulfilled, onRejected } = callback;
        //统一针对成功和失败的情况进行判断处理
    }
}

以上代码就是promise基本构造了,现在还差_handler()对成功还失败的处理,其实也很简单。在_resolve()和_reject()方法中,我们已经更新了状态。_handler()我们只需要判断下不同的状态就可以了。

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

        if (this.status === MyPromise.fulfilled && onFulfilled) {
            // 传入存储的值

           onFulfilled(this.value)
        }

        if (this.status === MyPromise.rejected && onRejected) {
            // 传入存储的错误信息
          onRejected(this.error)
        }
    }

写到这里基本已经实现了promise的基本功能,我们来测试下。定义一个方法fetchData(),通过传入true和false参数来判断成功和失败的情况,用定时器模拟下异步(接口调用)的情况。

function fetchData(success) {
    return new MyPromise((resolve, reject) => {
        console.log('调用promise')
        setTimeout(() => {
            if (success) {
                resolve("groot");
            } else {
                reject('error');
            }
        }, 2000);
    });
}

fetchData(true).then(data => {
    console.log(data); // 2秒后打印 groot
});

fetchData(false).then(null, (reason) => {
    console.log(reason); // 2秒后打印 error
});

可以看到打印信息,已经实现了promise的功能。但是我们都知道,promise是可以链式调用的,什么意思呢?简单点就是无限.then()下去,下一个.then()接收的参数,就是上一个.then()中return的数据。举个例子:我们调用第一个.then() 打印出data是groot,这个很好理解,但同时我们返回了一个groot wang,那么在下一个.then()中我们应该能接收到这个值,遗憾的是, 以目前我们的代码,返回的仍然是groot

fetchData(true).then((data) => {
    console.log(data); // groot
    return 'groot wang';
}, (err) => {}).then((data2) => {
    console.log(data2); // groot wang
});

如何实现链式调用

根据对promise的概念的理解我们知道,.then()返回的是一个新的promise,并且是把return的值传递给下一个.then()。所以我们思考需要改造下then()这个函数,让他实现两个功能,一是一个新的promise,二接收return后的值作为参数传递给下一个.then()。

 // 接收两个参数
    // onFulfilled 是成功时执行的函数
    // onRejected 是失败时执行的函数
    then(onFulfilled, onRejected) {
        // 这里可以理解为在注册事件
        // 也就是将需要执行的回调函数存储起来
        // 这两个函数 会在_resolve和_reject中调用
        // 我们new一个新的promise函数,同时接收下一个成功和失败的回调,一同存储到callbacks中,
        //这样保证.then()返回的是promise函数。
        return new  MyPromise((nextResolve,nextReject)=>{
            this.callbacks.push({
                onFulfilled,
                onRejected,
                nextResolve,
                nextReject
            });
        })

    }

then()已经改造完了,这时返回的已经是promise函数了,下一步需要改造_handler()使他可以把上一个.then()的值传给下一个.then()

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

         //判断等待的情况
        if (this.status === MyPromise.pending) {
            this.callbacks.push(callback);
            return;
        }
           
        //成功
        if (this.status === MyPromise.fulfilled ) {
            // 传入存储的值
            //已知onFulfilled是上一个.then()的回调函数,传入this.value就是return
            //的值。同时处理下onFulfilled没有传入的情况。

            const nextValue = onFulfilled?onFulfilled(this.value):undefined
            nextResolve(nextValue);

            return
        }


        //失败
        if (this.status === MyPromise.rejected ) {
            // 传入存储的错误信息
            // 同成功的处理...
            const nextReason = onRejected ? onRejected(this.reason) : undefined
            nextReject(nextReason);
            return;
        }
    }

此时再链式调用一下:

fetchData(true).then((data) => {
    console.log(data); //2秒后 groot
    return 'groot wang';
}, (err) => {}).then((data2) => {
    console.log(data2); //2秒后 groot wang
});

简易的promise函数功能实现。