手写Promise

76 阅读3分钟

手写promise

根据promise A+规范 可以得出如下 需要注意的点:
1.为了防止调用then的时候,this指向的不是实例对象,所以需要用一个self保存this值.
2.关于定时器的使用,resolve和reject函数是需要加定时器的,这是因为.then是微任务,确保onFulfilled异步执行,且在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。如果有异步函数,resolve在then后面执行.还有onFulfilled函数也需要加定时器,这个为了模仿微服务,加一个异步

手写promise总共分三个阶段

promise的状态

有三种:pending,fulfilled,rejected.pending表示待定,fulfilled表示成果,rejected,表示失败

then方法

.then是一个函数,有两个参数onFulfilled,onRejected
onFulfiled:状态为fulfilled的时候的回调函数,只能被执行一次,第一个参数是promise的value.
onRejected:状态为rejected的时候的回调函数,只能被执行一次,第一个参数是promise的reason.
then可以多次调用,用一个数组存储回调函数,状态变化时会按注册顺序调用
为了解决链式调用,.then会返回一个新promise

promise2 = promise1.then(onFulfilled, onRejected);
  • 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程[[Resolve]](promise2, x)
  • 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
  • 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
  • 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因

解决函数

运行 [[Resolve]](promise, x) 需遵循以下步骤:

x 与 promise 相等

如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise

x 为 Promise

如果 x 为 Promise ,则使 promise 接受 x 的状态 注4

  • 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
  • 如果 x 处于执行态,用相同的值执行 promise
  • 如果 x 处于拒绝态,用相同的据因拒绝 promise

x 为对象或函数

如果 x 为对象或者函数:

  • 把 x.then 赋值给 then 注5

  • 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise

  • 如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise:

    • 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)

    • 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise

    • 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用

    • 如果调用 then 方法抛出了异常 e

      • 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
      • 否则以 e 为据因拒绝 promise
    • 如果 then 不是函数,以 x 为参数执行 promise

  • 如果 x 不为对象或者函数,以 x 为参数执行 promise

function MyPromise(executor) {
    this.state = 'pending';
    this.onFulfilledCallback = [];
    this.onRejectedCallback = [];
    const self = this;
    function resolve(value) {
        setTimeout(function () {
            if (self.state === 'pending') {
                self.state = 'fulfilled';
                self.data = value;
                for (let i = 0; i < self.onFulfilledCallback.length; i++) {
                    self.onFulfilledCallback[i](value);
                }
            }
        })

    }
    function reject(reason) {
        setTimeout(function () {
            if (self.state === 'pending') {
                self.state = 'rejected';
                self.data = reason;
                for (let i = 0; i < self.onRejectedCallback.length; i++) {
                    self.onRejectedCallback[i](reason);
                }
            }
        })

    }
    try {
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {

    const self = this;
    let promise2;

    return (promise2 = new MyPromise(function (resolve, reject) {

        if (self.state === 'fulfilled') {

            setTimeout(function () {
                //如果onFulfilled是一个函数,运行,然后进行Promise解决过程,如果不是就忽略
                if (typeof onFulfilled === 'function') {
                    try {
                        const x = onFulfilled(self.data);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }

                } else {
                    resolve(self.data);
                }
            });
        } else if (self.state === 'rejected') {
            setTimeout(function () {
                if (typeof onRejected === 'function') {
                    try {
                        const x = onRejected(self.data);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                } else {
                    reject(self.data);
                }
            })
        } else if (self.state === 'pending') {
            self.onFulfilledCallback.push(function (promise1Value) {
                if (typeof onFulfilled === 'function') {
                    try {
                        const x = onFulfilled(self.data)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error);
                    }
                } else {
                    resolve(promise1Value);
                }
            });
            self.onRejectedCallback.push(function (promise1Reason) {
                if (typeof onRejected === 'function') {
                    try {
                        const x = onRejected(self.data);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                } else {
                    reject(promise1Reason);
                }
            });
        }



    }));

};
function resolvePromise(promise2, x, resolve, reject) {

    if (promise2 === x) {
        return reject(new TypeError('循环利用'));
    }
    if (x instanceof MyPromise) {
        if (x.state === 'pending') {
            //等待它转变,所以执行和上面一样的操作
            x.then(function (value) {
                resolvePromise(promise2, value, resolve, reject)
            }, reject);
        } else if (x.state === 'fulfilled') {
            //如果这个promise是fulfilled,那么promise2就直接解决了
            resolve(x.data);
        } else if (x.state === 'rejected') {
            reject(x.data);
        }
        return;
    }
    if (x && (typeof x === "object" || typeof x === "function")) {
        let isCalled = false;

        try {
            let then = x.then;
            if (typeof then === "function") {
                then.call(x,
                    function rs(y) {
                        if (isCalled) return;
                        isCalled = true;
                        return resolvePromise(promise2, y, resolve, reject);
                    }, 
                    function rj(e) {
                        if (isCalled) return;
                        isCalled = true;
                        return reject(e);
                    }
            );
            } else {
                resolve(x);
            }
        } catch (error) {
            if (isCalled) return;
            isCalled = true;
            reject(error);
        }
    } else {
        resolve(x);
    }
}

静态方法

Promise.all,race,allsettled,resolve,reject

//如果传入的参数时promise那就直接返回,如果不是就返回一个状态为fulfilled的promise
Promise.resolve=(value)=>{
    if(value instanceof Promise){
        return value
    }
    else{
        return new Promise((resolve, reject) => {
        resolve(value)
    })
}
}
//直接返回一个状态为reject的promise
Promise.reject=(reason)=>{
    return new Promise((resolve, reject) => {
        reject(reason)
    })
}
//返回一个promise,如果所有都成功才是fulfilled,返回一个带所有promise的数组,有一个reject那就reject
Promise.all=(promises)=>{
    let count =0;//定义计数器,用来知道有几个返回成功
    let len = promises.length;
    let result = [];//所有 promise 的 resolve之后返回的结果

    return new Promise((resolve,reject)=>{
        promises.forEach((params,index)=>{
            Promise.resolve(params).then((value)=>{
                count++;
                result[index]=value;
                if(count== len){
                    resolve(result)
                }
            },(reason)=>{
                reject(reason)
            })
        })
    })
}
//只要有一个改变状态就返回,所以对每一个promise.promise.then(resolve,reject).只要有一个参数改变就返回
Promise.rece=(promises)=>{
    return new Promise((resolve, reject) => {
        promises.forEach((p)=>{
            Promise.resolve(p).then(resolve).catch(reject)
        })
    })
}
//所有promise都改变状态才返回,返回一个数组,状态永远是fulfilled.
Promise.allSettled=(promises)=>{

    let count =0;
    let result=[];
    let len = promises.length;
    return new Promise((resolve, reject) => {

        promises.forEach((p,i)=>{
            Promise.resolve(p).then((value)=>{
                count++;
                result[i]={
                    state:'fulfilled',
                    value:value
                };
                if(count == len){
                    resolve(result)
                }
            },(reason)=>{
                count++;
                result[i]={
                    state:'rejected',
                    reason:reason
                };
                if(count == len){
                    resolve(result)
                }
            }
              
            )
        })
    })
}