手写Promise

177 阅读7分钟

Promise分三步

  • 同步
  • 异步
  • 承诺

同步

class Promise{
    constructor(executor){
       //保存状态值
       this.state='pending'
       //保存——成功时传入参数
       this.value=undefined
       //保存——失败时原因
       this.reson=undefined
       
       //成功时更改状态,保存参数
       let resolve=value=>{
           if(this.state==='pending'){
               this.value=value
               this.state='fulfilled'
           }
       }
       //失败时更改状态,保存失败原因
       let reject=reson=>{
           if(this.state==='pending'){
               this.reson=reson
               this.state='rejected'
           }
       }
       try{
           executor(resolve,reject)
       }catch(err){
           reject(err)
       }
    }
    then(onFulfilled,onRejected){
        //onFulfilled返回的是成功时的函数(例:下面pro.then的就是res => res)
        //onRejected返回的是失败时的函数(例:下面pro.then的就是res => res)
        if(this.state==='fulfilled'){
            onFulfilled(this.value)
        }
        if(this.state==='rejected'){
            onRejected(this.reson)
        }
        if(this.state==='pending'){
            
        }
    }
}

let pro = new Promise1((resolve, reject) => resolve(2333))
pro.then(res => res)//res=2333

这样一个简单的同步Promise就完成了

异步

调用异步函数会出现问题

let pro = new Promise1((resolve, reject) => {
        setTimeout(res => {
            resolve(res)
        }, 0, 1000)
    })
    pro.then(res => res)//res是undefined

在Promise1中执行函数使用了异步函数(这里有栈和队列的问题)

阅览器执行顺数是同步->微任务->宏任务),在这里then中执行是同步的(实际上then中是微任务)

所以pro.then(res => res),会优先于resolve执行。执行then时状态(state)和参数(value)都没有改变

class Promise{
    constructor(executor){
       //保存状态值
       this.state='pending'
       //保存——成功时传入参数
       this.value=undefined
       //保存——失败时原因
       this.reson=undefined
       
       //用于保存成功异步时的执行函数
       this.onFulfillCallbacks=[]
       //用于失败成功异步时的执行函数
       this.onRejectCallbacks=[]
       //成功时更改状态,保存参数
       let resolve=value=>{
           if(this.state==='pending'){
               this.value=value
               this.state='fulfilled'
               this.onFulfillCallbacks.forEach(fn => fn())
           }
       }
       //失败时更改状态,保存失败原因
       let reject=reson=>{
           if(this.state==='pending'){
               this.reson=reson
               this.state='rejected'
               this.onRejectCallbacks.forEach(fn => fn())
           }
       }
       try{
           executor(resolve,reject)
       }catch(err){
           reject(err)
       }
    }
    then(onFulfilled,onRejected){
        //onFulfilled返回的是成功时的函数(例:下面pro.then的就是res => res)
        //onRejected返回的是失败时的函数(例:下面pro.then的就是res => res)
        if(this.state==='fulfilled'){
            onFulfilled(this.value)
        }
        if(this.state==='rejected'){
            onRejected(this.reson)
        }
        if(this.state==='pending'){
            this.onFulfillCallbacks.push(() => onFulfilled(this.value))
            this.onRejectCallbacks.push(() => onRejected(this.reson))
        }
    }
}

这样就完成promise的异步调用了。

先看一下同步、异步的执行顺序

let pro1 = new Promise1((resolve, reject) => resolve(res) )
pro1.then(res => res)//res=2333

同步执行顺序:

constructor=>resolve=>

  • 改变state状态为'fulfilled'
  • 保存value传值

then=>

  • 进入'fulfilled'状态
  • 执行then的回调函数
let pro2 = new Promise1((resolve, reject) => {
    setTimeout(res => {
        resolve(res)
    }, 0, 2333)
})
pro2.then(res => res)//res=2333

异步执行顺序:

constructor=>

  • 因异步原因,未执行任何操作

then=>

  • 进入'pending'状态
  • 保存onFulfillCallbacks与onRejectCallbacks所有的回调函数并传参

resolve=>

  • 异步结束,执行resolve
  • 改变state状态为'fulfilled'
  • 保存value传值
  • 执行onFulfillCallbacks中的所有函数

承诺

promise有链式调用: pro2.then(res => res) .then(res => res) .then(res => res)

class Promise {
        constructor(executor) {
            this.state = "pending";
            this.value = undefined;
            this.reson = undefined;
            this.onFulfillCallbacks = [];
            this.onRejectCallbacks = [];
            let resolve = value => {
                if (this.state === "pending") {
                    this.value = value;
                    this.state = "fulfilled";
                    this.onFulfillCallbacks.forEach(fn => fn());
                }
            };
            let reject = reson => {
                if (this.state === "pending") {
                    this.value = reson;
                    this.state = "fulfilled";
                    this.onRejectCallbacks .forEach(fn => fn());
                }
            };
            executor(resolve, reject);
        }
        then(onFulfilled, onRejected) {
            onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
            onRejected  = typeof onRejected === "function" ? onRejected : err => { throw err; };
            let promise2 = new Promise((resolve, reject) => {
                if (this.state === "fulfilled") {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvepromise(promise2, x, resolve, reject);
                        } catch (error) {
                            reject(error);
                        }
                    }, 0);
                }
                if (this.state === "rejected") {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reson);
                            resolvepromise(promise2, x, resolve, reject);
                        } catch (error) {
                            reject(error);
                        }
                    }, 0);
                }
                if (this.state === "pending") {
                    this.onFulfillCallbacks.push(() => {
                        setTimeout(() => {
                            try {
                                let x = onFulfilled(this.value);
                                resolvepromise(promise2, x, resolve, reject);
                            } catch (error) {
                                reject(error);
                            }
                        }, 0);
                    });
                    this.onRejectCallbacks.push(() => {
                        setTimeout(() => {
                            try {
                                let x = onRejected(this.reson);
                                resolvepromise(promise2, x, resolve, reject);
                            } catch (error) {
                                reject(error);
                            }
                        }, 0);
                    });
                }
            });
            return promise2;
        }
    }

constructor中没有什么变化

主要是then中有一些

1, 这里onFulfilled和onRejected做一下传值处理,只接受function(函数),不是就直接使用默认的函数。

避免不传或奇怪的传参出现问题。

onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
onRejected  = typeof onRejected === "function" ? onRejected : err => { throw err; };

2, 使用Promise并return值

let promise2 = new Promise((resolve, reject) => {
})
return promise2;

//Promise链式调用后面的res传参都是前一个return返回的参数
new Promise((resolve, reject) => resolve(1))
.then(res=>res+1) //res=1
.then(res=>res+1) //res=2
.then(res=>res+1) //res=3

3,这里使用setTimeout,因为then返回是异步函数(不过setTimeout是宏任务,你们可以自己试试怎么实现微任务)

使用try catch来获取错误

关键就是resolvepromise,这是实现承诺的关键函数

setTimeout(() => {
    try {
        let x = onFulfilled(this.value);
        resolvepromise(promise2, x, resolve, reject);
    } catch (error) {
        reject(error);
    }
}, 0);

resolvepromise

  • promise2:then中已promise返回,主要查看onFulfilled和onRejected是否有执行的函数
  • x:当前then的返回值,没有就是undefined
  • resolve和reject就是constructor中的执行函数
function resolvepromise(promise2, x, resolve, reject) {
        //promise2与x指向同一对象,已typeerror为拒因拒绝执行
        if (promise2 === x) {
            return reject(new TypeError("..."));
        }
        //当x为函数或对象时执行,否则已x为拒因拒绝执行
        if (x != null && (typeof x === "function" || typeof x === "object")) {
            let called;//promise中resolve和reject只执行一个
            try {
                let then = x.then;
                //如果x.then是函数,将x作为函数的作用域调用
                if (typeof then === "function") {
                    then.call(x,
                        y => {
                            if (called) return;
                            called = true;
                            resolvepromise(promise2, y, resolve, reject);
                        },
                        e => {
                            if (called) return;
                            called = true;
                            reject(error);
                        }
                    );
                } else {
                //如果x是对象,已x为值执行promise
                    resolve(x);
                }
            } catch (error) {
                //如果x.then抛出异常e,则以e为拒因拒绝执行
                if (called) return;
                called = true;
                reject(error);
            }
        } else {
            resolve(x);
        }
}

这里详细列一下resolvepromise的关键点,自己写的时候可以根据关键点去记

  • 拒绝执行就是执行reject
  • 执行就是执行resolve

1, x与Promise相等

  • 如果x与Promise指向同一对象,已TypeError为拒因拒绝执行

2,x为Promise(x != null && (typeof x === "function" || typeof x === "object"))这里

  • x处于等待状态'pending',promise保存等待直至x被执行或拒绝
  • x处于执行状态'fulfilled',执行promise
  • x处于拒绝状态'rejected',拒因promise

3,x为对象或函数

  • 把x.then赋值给then
  • 如果x.then抛出异常e,则以e为拒因拒绝执行
  • 如果x是函数,将x作为函数的作用域调用
  • 如果x是对象,已x为值执行promise

好了,这样基本的Promise就完成了

class Promise {
        constructor(executor) {
            this.state = "pending";
            this.value = undefined;
            this.reson = undefined;
            this.onFulfillCallbacks = [];
            this.onRejectCallbacks = [];
            let resolve = value => {
                if (this.state === "pending") {
                    this.value = value;
                    this.state = "fulfilled";
                    this.onFulfillCallbacks.forEach(fn => fn());
                }
            };
            let reject = reson => {
                if (this.state === "pending") {
                    this.value = reson;
                    this.state = "fulfilled";
                    this.onRejectCallbacks .forEach(fn => fn());
                }
            };
            executor(resolve, reject);
        }
        then(onFulfilled, onRejected) {
            onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
            onRejected  = typeof onRejected === "function" ? onRejected : err => { throw err; };
            let promise2 = new Promise((resolve, reject) => {
                if (this.state === "fulfilled") {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvepromise(promise2, x, resolve, reject);
                        } catch (error) {
                            reject(error);
                        }
                    }, 0);
                }
                if (this.state === "rejected") {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reson);
                            resolvepromise(promise2, x, resolve, reject);
                        } catch (error) {
                            reject(error);
                        }
                    }, 0);
                }
                if (this.state === "pending") {
                    this.onFulfillCallbacks.push(() => {
                        setTimeout(() => {
                            try {
                                let x = onFulfilled(this.value);
                                resolvepromise(promise2, x, resolve, reject);
                            } catch (error) {
                                reject(error);
                            }
                        }, 0);
                    });
                    this.onRejectCallbacks.push(() => {
                        setTimeout(() => {
                            try {
                                let x = onRejected(this.reson);
                                resolvepromise(promise2, x, resolve, reject);
                            } catch (error) {
                                reject(error);
                            }
                        }, 0);
                    });
                }
            });
            return promise2;
        }
    }
    function resolvepromise(promise2, x, resolve, reject) {
        //promise2与x指向同一对象,已typeerror为拒因拒绝执行
        if (promise2 === x) {
            return reject(new TypeError("..."));
        }
        //当x为函数或对象时执行,否则已x为拒因拒绝执行
        if (x != null && (typeof x === "function" || typeof x === "object")) {
            let called;//promise中resolve和reject只执行一个
            try {
                let then = x.then;
                //如果x.then是函数,将x作为函数的作用域调用
                if (typeof then === "function") {
                    then.call(x,
                        y => {
                            if (called) return;
                            called = true;
                            resolvepromise(promise2, y, resolve, reject);
                        },
                        e => {
                            if (called) return;
                            called = true;
                            reject(error);
                        }
                    );
                } else {
                //如果x是对象,已x为值执行promise
                    resolve(x);
                }
            } catch (error) {
                //如果x.then抛出异常e,则以e为拒因拒绝执行
                if (called) return;
                called = true;
                reject(error);
            }
        } else {
            resolve(x);
        }
}

最后在写一点Promise的一些方法吧

1,Promise.resolve

    Promise.resolve = function (val) {
        return new Promise((resolve, reject) => {
            resolve(val);
        });
    };

2,Promise.reject

    Promise.resolve = function (val) {
        return new Promise((resolve, reject) => {
            resolve(val);
        });
    };

3,Promise.catch

    Promise.catch=function(fn){
        return this.reject(null,fn)
    }

4,Promise.race

    Promise.race=function(promises){
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(resolve, reject);
            }
        });
    }

5,Promise.all

    Promise.all = function (promises) {
        let arr = [];
        let i = 0;
        let processData=function(index, data) {
                arr[index] = data;
                i++;
                if (i == promises.length) {
                    resolve(arr);
                }
        }
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(data => {
                    processData(i, data);
                }, reject);
            }
        });
    };

好了,没了

给个三连吧哐哐哐,gkd