一步步手写promise

promise的代码遵循以下几点
1.promise状态的不可变性,只能由pending到fulfilled,或者pending到rejected;
2.promise支持异步,采用setTimeout;
3.promise中采用.then的链式调用,原理是返回新的promise,而不是返回自身。

Promises/A+规范

then方法里做了两件事,1.把前面resolve的值传到回调函数中;2.把当前then方法中的返回值,传递到下一个then方法里

class myPromise {
    constructor(exc) {
        this.success = null
        this.fail = null
        this.state = "pending"
        this.resolveArr = []
        this.rejectArr = []
        let resolve = (value) => {
            if (this.state == "pending") {
                this.state = "fulfilled"
                this.success = value
                //增加resolve时遍历执行
                this.resolveArr.forEach(fn => fn())
            }
        }
        let reject = (value) => {
            if (this.state == "pending") {
                this.state = "rejected"
                //增加reject时遍历执行
                this.fail = value
                this.rejectArr.forEach(fn => fn())
            }
        }
        try {
            exc(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }
    then(onFulfilled, onRejected) {
        // 判断是否为函数,不是函数转为函数的格式
        onFulfilled = typeof onFulfilled == "function" ? onFulfilled : (value) => value
        onRejected = typeof onRejected == "function" ? onRejected : (err) => { throw err }
        let promise2 = new myPromise((resolve, reject) => {
            if (this.state == "fulfilled") {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(this.success)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error);
                    }
                }, 0)
            }
            if (this.state == "rejected") {
                setTimeout(() => {
                    try {
                        const x = onRejected(this.fail)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error);
                    }
                }, 0)

            }
            //增加pending判断
            if (this.state == "pending") {
                this.resolveArr.push(() => {
                    setTimeout(() => {
                        try {
                            const x = onFulfilled(this.success)
                            resolvePromise(promise2, x, resolve, reject)

                        } catch (error) {
                            reject(error);
                        }
                    }, 0)
                })
                this.rejectArr.push(() => {
                    setTimeout(() => {
                        try {
                            const x = onRejected(this.fail)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error);
                        }
                    }, 0);
                })
            }
        })
        return promise2
    }
    catch(fn) {
        this.then(null, fn)
    }
}

x值可能出现以下几种类型:普通值,对象,函数,promise。因为promise的类型属于object,所以只需要判断3种类型:普通值,对象,函数。如果可以执行.then方法说明返回值是个promise,那么就可以拿到promise中resolve的值,接着继续判断值类型,依次类推,递归执行此方法。

const resolvePromise = (promise2, x, resolve, reject) => {
    if (promise2 == x) {
        // throw ("不能循环引用自己")
        reject(new TypeError("Chaining cycle detected for promise"));
    }
    // 防止多次调用
    let called;
    if ((typeof x == "object" && x !== null) || typeof x === 'function') {
        // promise实例x, x类型为object, x.then类型为function
        try {
            // 这边直接使用then的话,下面要改变this指向
            let then = x.then
            if (typeof then === "function") {
                then.call(x,
                    (res) => {
                        if (called) return;
                        called = true;
                        //如果内部还是promise,则递归调用
                        resolvePromise(promise2, res, resolve, reject)
                    },
                    err => {
                        if (called) return;
                        called = true;
                        // 直接抛异常,不再深层次判断
                        reject(err)
                        // resolvePromise(promise2, err, resolve, reject)
                    })
            } else {
                // 对于x类型为function
                if (called) return;
                called = true;
                resolve(x);
            }
        } catch (err) {
            if (called) return;
            called = true;
            reject(err)
        }
    } else {
        // 对于普通值
        if (called) return;
        called = true;
        resolve(x)
    }
}

附赠resolve,reject方法

myPromise.resolve = (val) => {
  return new myPromise((resolve, reject) => {
    // 相当于执行constructor中的resolve方法
    resolve(val);
  });
};
myPromise.reject = (val) => {
  return new myPromise((resolve, reject) => {
    reject(val);
  });
};

此处不直接使用resolve而使用myPromise.resolve,是因为resolve后状态就改变了,整个myPromise.all就结束了

myPromise.all = (promises) => {
  return new myPromise((resolve, reject) => {
    let count = 0;
    const result = [];
    for (let i = 0; i < promises.length; i++) {
      // 此处不直接使用resolve而使用myPromise.resolve是因为,resolve后状态就改变了,整个myPromise.all就结束了
      const promise = myPromise.resolve(promises[i]).then(res => res)
      promise.then((res) => {
          result.push(res);
          count++;
          if (count === promises.length) {
            resolve(result);
          }
        })
        .catch((err) => {
          reject(err);
        });
    }
  });
};

测试自己写的对不对?

myPromise.deferred = function () {
  const defer = {}
  defer.promise = new myPromise((resolve, reject) => {
    defer.resolve = resolve
    defer.reject = reject
  })
  return defer
}

module.exports = myPromise

运行命令

npm i promises-aplus-tests -g 
npx promises-aplus-tests promise.js 

在这里插入图片描述

1.为何promise要resolve()之后才能.then?
此处的resolve指的是constructor中的resolve方法,当resolve执行完之后,状态就会由pending转为fulfilled。当状态为fulfilled,then方法对应的方法才会继续执行,所以then方法的执行是通过判断状态的改变。

2.then方法中的回调函数为何能取到reolve的值?
onFulfilled(this.success)会通过回调函数把值传出来,同时也会resolve当前函数的返回值,传递给下一个.then方法中,当不是普通值时会进一步深层次判断,但最终都要resolve,所以想要传递下去必须要resolve。

3.对于值穿透的理解?
值穿透会发生在then方法参数不是一个函数,那么就会把它转为一个函数,暴露的都是传入的参数,所以才会发生值穿透,若不想值穿透,传入函数即可。因为如果是回调函数,则暴露相应的返回值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值