Promise手写,带你了解Promise的基本知识,适合新手哦!

415 阅读18分钟

Promise手写

这里是对Promise的一些基本功能进行手写,其中包含各种API的讲解和实现,从0开始构建一个完整的Promise,适合新手。

初始结构搭建

首先我们可以根据Promise的实际使用观察出,当我们需要创建一个Promise对象时,需要传递一个参数(resolve,reject)=>{}

let p = new Promise((resolve,reject)=>{
    reoslve('OK');
})

因此在我们声明自己的Promise函数时,需要传递一个executor形参,也就是执行器。

function Promise(executor){};

resolve和reject的实现

  • 当我们的实参传递给执行器的时候,promise内部会同步调用函数 。

    function Promise(executor){
        executor(resolve,reject);
    }
    
  • 接下来让我们来声明一下resolvereject,通过对原对象观察可知,resolve接收了一个实参。则我们可以将它声明为一个函数并传递一个形参;reject也是同理。

    function Promise(executor){
        //声明resolve
        function resolve(data){
            
        }
        
        //声明reject
     	function reject(data){
            
        }
        
        //同步调用【执行器函数】
        executor(resolve,reject);
    }
    

在这里说明一下,因为是自己手写Promise,所以的命名都是自己设定的。简单来讲就是说,你可以命名这个执行器函数为executor,也可以是a,b,c等等,只要保证调用不出错就可以了。除此之外,当我们未引入该手写promise文件时,new Promise是全局的promise。引入后便是自己手写文件中的promise,不会冲突。

  • 下面来进行函数的代码实现。我们知道 resolve函数有两大主要功能:

    1)修改对象状态为fulfilled

    2)是指对象的结果值

    实际上这两个都是实例对象身上的属性,promiseStatepromiseResult

    因此需要先添加这两个属性并设置初始值。

    reject也是同理。

    function Promise(executor){
        //添加属性
        this.PromiseState = "pending";//pending为未决定的promise状态
        this.promiseResult = null;
        //保存实例对象的this值
        const self = this;
        
        //声明resolve
        function resolve(data){
            //1.修改对象状态
            //这里不能直接使用this.promiseState的原因是resolve是直接调用的,在这里指向windows,因此需要先保存 this的值再使用,或者使用箭头函数。
            self.PromiseState = 'fulfilled';//fulfilled表示成功的状态,和resolve一样
            //2.设置对象结果值
            self.PromiseResult = data;
        }
        
        //声明reject
     	function reject(data){
             //1.修改对象状态
            self.PromiseState = 'rejected';//rejected表示失败的状态
            //2.设置对象结果值
            self.PromiseResult = data;
        }
        
        //同步调用【执行器函数】
        executor(resolve,reject);
    }
    

throw抛出异常改变状态

我们知道,promise改变状态有三种办法,除了resolvereject,还有throw抛出错误。这里我们使用tey{}catch{}方法。

先简单介绍一下这个方法

try{
    function one()
}catch(e){
    function two(e)
}
//如果throw 'OK',则执行two('OK');否则执行one()

当我们抛出错误时,promise状态会变成失败,且throw的实参会传递给reject

function Promise(executor){
    //添加属性
    this.PromiseState = "pending";
    this.promiseResult = null;
    //保存实例对象的this值
    const self = this;
    
    //声明resolve
    function resolve(data){
        //1.修改对象状态
        self.PromiseState = 'fulfilled';
        //2.设置对象结果值
        self.PromiseResult = data;
    }
    
    //声明reject
 	function reject(data){
         //1.修改对象状态
        self.PromiseState = 'rejected';
        //2.设置对象结果值
        self.PromiseResult = data;
    }
    
    //抛出异常
    try{
        //同步调用【执行器函数】
     	executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}

Promise对象状态只能改变一次

我们知道,promise对象的状态初始为pening且只能改变一次。因此我们需要接入一个判断,判断当前promise状态是否改变,也就是是否为初始值pending

在这里为了优化代码,我们也可以设置“在resolvereject中判断promise,当它的状态不为初始值时,直接返回,不再继续执行resolvereject

function Promise(executor){
    //添加属性
    this.PromiseState = "pending";
    this.promiseResult = null;
    //保存实例对象的this值
    const self = this;
    
    //声明resolve
    function resolve(data){
        //判断promise状态是否已改变
        if(self.PromiseState !== "pending")
            return;
        //1.修改对象状态
        self.PromiseState = 'fulfilled';
        //2.设置对象结果值
        self.PromiseResult = data;
    }
    
    //声明reject
 	function reject(data){
        //判断promise状态是否已改变
        if(self.PromiseState !== "pending")
            return;
         //1.修改对象状态
        self.PromiseState = 'rejected';
        //2.设置对象结果值
        self.PromiseResult = data;
    }
    
    //抛出异常
    try{
        //同步调用【执行器函数】
     	executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}

以上基本就是promise的基本构造了,接下来我们将继续构建一些promise常用的API。

then方法执行回调

  • 首先还是观察promise.then方法的使用情况。

    p.then(value=>{
        console.log(value);
    },reason=>{
        console.warn(reason);
    })
    

    可以知道,then方法需要传递两个参数(onResolved,onReject),其中onResolved函数是成功的 回调函数(value)=>{};onReject是失败的回调函数(reason)=>{}

    则添加then方法

    Promise.prototype.then = function(onResolved,onRejected){
        
    };
    
  • 判断回调哪个函数。

    我们需要先知道promise的状态才能够知道需要执行onResolved还是onRejected函数,因此在then方法中先增加一个判断状态。

    Promise.prototype.then = function(onResolved,onRejected){
        //调用回调函数
        //这里可以直接使用this.promiseState是因为then方法是被p调用的,而p是一个promise对象,因此 这里的this实际上指向的是p这个promise对象。
        if(this.PromiseState === 'fulfilled'){
            onResolved();
        }
        if(this.PromiseState === 'rejected'){
            onRejected();
        }
    };
    
  • 传递参数

    我们观察到当调用onResolved时实际上是传递了一个value值,同理onRejected传递了reason值,这两个值实际上保存在PromiseResult中,因此可以设置this.PromiseResult为这两个函数的形参。

    Promise.prototype.then = function(onResolved,onRejected){
        //调用回调函数
        if(this.PromiseState === 'fulfilled'){
            onResolved(this.PromiseResult);
        }
        if(this.PromiseState === 'rejected'){
            onRejected(this.PromiseResult);
        }
    };
    

在这里可以对自己写的做一下检查,查看最基本的resolve,reject,throw在then方法中是否能够输出result。

异步任务回调的执行

promise是支持异步使用的,我们可以添加一个定时器尝试一下。

let p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('OK');
        //reject('error');
        //throw 'error';
    },1000)
})

p.then(value=>{
    console.log(value);
},reason=>{
    console.log(reason);
})

添加定时器后,我们就需要先调用then方法,后再改变对象状态。注意,这里只是调用then方法,由于函数状态未改变,因此不能直接执行回调。此时对象状态仍然是pending。因此我们需要判断当对象状态为pending时需要执行的操作。

那么我们分析可以知道,无论什么时候调用then方法,我们都需要在状态改变后才能执行回调。因此我们可以将调用回调函数写在改变状态函数之后。使其既可以“先改变状态再调用then”,也可以”先调用then再改变状态“两种操作。

由于回调函数和改变状态函数(resolve和reject)是两个不同函数内的函数,无法直接调用。但是他们作用于同一个对象身上,因此我们可以在这个对象身上添加一个callback属性保存这两个回调函数。这样resolvereject就可以调用到对应的回调函数了。

function Promise(executor){
    this.PromiseState = "pending";
    this.promiseResult = null;
    const self = this;
    //添加保存回调函数的属性
    this.callback = {};
    
    function resolve(data){
        if(self.PromiseState !== "pending")
            return;
        self.PromiseState = 'fulfilled';
        self.PromiseResult = data;
        //调用成功的回调函数
        //调用方法:这里需要首先判断是先改变状态还是先调用then。判断方法就是看调用then方法时promise的状态是否改变,如果改变,则callback内为空,按照原本的设定执行;如果不改变,则callback内会存入onResolved和onRejected。因此在这里,可以通过检查callback内部是否存在这两个函数来判断执行状态。
        if(self.callback.onResolved){
            //这里的参数实际上就是resolve的参数,也就是PromiseResult。
            self.callback.onResolved(data);
        }
    }
    
 	function reject(data){
        if(self.PromiseState !== "pending")
            return;
        self.PromiseState = 'rejected';
        self.PromiseResult = data;
        //调用失败的回调函数
        //调用方法同resolve
  	 	if(self.callback.onRejected){
            self.callback.onRejected(data);
        }
    }
    
    try{
     	executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}

Promise.prototype.then = function(onResolved,onRejected){
    if(this.PromiseState === 'fulfilled'){
        onResolved(this.PromiseResult);
    }
    if(this.PromiseState === 'rejected'){
        onRejected(this.PromiseResult);
    }
    if(this.PromiseState === 'pending'){
        //保存回调函数
        this.callback =  {
            onResolved:onResolved,
            onRejected:onRejected
        }
    }
};

上面代码较之前代码共修改了四 个地方:1.在对象添加callback属性。2.在then方法内保存回调函数。3.在resolve中添加成功回调函数的调用。4.在reject中添加失败回调函数的调用。

多个回调的实现

我们知道promise可以同时指定 多个回调。比如:

let p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('OK');
        //reject('error');
        //throw 'error';
    },1000)
});

//指定回调-1
p.then(value=>{
    console.log(value);
});

//指定回调-2
p.then(value=>{
    alert(value);
});
//两个回调会同时执行。

然而在我们的代码中,因为存在定时器,所以当回调-1指定时,会在callback中保存一次回调函数;当指定回调-2时,又会保存一次,则回调-1就被覆盖了。

因此,我们可以将callback声明成为一个数组,用以储存不同回调。

function Promise(executor){
    this.PromiseState = "pending";
    this.promiseResult = null;
    const self = this;
    //添加保存回调函数的数组属性
    this.callbacks = [];
    
    function resolve(data){
        if(self.PromiseState !== "pending")
            return;
        self.PromiseState = 'fulfilled';
        self.PromiseResult = data;
        //那么此时调用回调函数就不能直接调用callback了,而是遍历callbacks数组。
        //此时也不需要再进行判断,因为如果数组为空,便不能执行回调。
        /*if(self.callback.onResolved){
            self.callback.onResolved(data);
        }*/
        //这里的item是callbacks数组的元素,每个item都是一个包含有onResolved和onRejected的对象。
        self.callbacks.forEach(item =>{
            item.onResolved(data);
        })
    }
    
 	function reject(data){
        if(self.PromiseState !== "pending")
            return;
        self.PromiseState = 'rejected';
        self.PromiseResult = data;
  	 	/*if(self.callback.onRejected){
            self.callback.onRejected(data);
        }*/
        self.callbacks.forEach(item =>{
            item.onRejected(data);
        })
    }
    
    try{
     	executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}

Promise.prototype.then = function(onResolved,onRejected){
    if(this.PromiseState === 'fulfilled'){
        onResolved(this.PromiseResult);
    }
    if(this.PromiseState === 'rejected'){
        onRejected(this.PromiseResult);
    }
    if(this.PromiseState === 'pending'){
        //那么这里就是新的回调向数组后面添加
        this.callbacks.push({
            onResolved:onResolved,
            onRejected:onRejected
        })
    }
};

此段代码较改进的地方有四个:1.将callback对象改为数组,其内部储存的每个元素为对象。2.在then方法中 将保存callback对象改为向callbacks数组中 添加对象元素。3.在resolve中修改判断和调用为遍历callbacks数组。4.reject同理。

修改then方法返回结果的实现

then方法的返回结果是一个promise对象,其状态由内部回调函数的执行结果决定。如果执行结果返回了一个非promise类型的结果 ,则then方法返回的promise状态为成功;如果执行结果返回的是一个promise类型的结果,则这个promise的状态会决定then方法返回的promise对象状态。

  • 首先需要将then方法的返回结果设置成一个promise对象
  • 获取回调函数的执行结果,判断其是否为promise类型
  • 通过判断执行结果“是否为promise类型”和“如果是promise类型那么其状态”来改变then返回的promise的状态
  • 除了resolve和reject,我们还需要考虑回调函数的执行结果如果是抛出异常,则then方法的结果就变成失败的状态
Promise.prototype.then = function(onResolved,onRejected){
    //将then方法的返回值设置成为promise对象类型
    return new Promise((resolve,reject)=>{
        if(this.PromiseState === 'fulfilled'){
            try{
                 //获取回调函数的执行结果
            	 let result = onResolved(this.PromiseResult);
             	//判断
             	if(result instanceof Promise){
                 	//如果是promise类型,则该result可以调用then方法,可以通过调用then方法来设置不同状态的promise对于then的返回值状态的影响
                	 result.then(v =>{
                    	//这里的resolve内部指向result,因此改变的是result的状态,也就是then方法返回的promise状态。
                     	//成功的结果为v
                    	 resolve(v);
                	 },r =>{
                    	 //失败的结果为r
                   	 	 reject(r);
                	 })
            	 }else{
                 	//执行结果为非promise类型则then方法返回的promise状态变为成功,该promise的成功的值应该是回调函数执行的结果,也就是result
                	 resolve(result);
             	 }
            }catch(e){
                reject(e);
            }
    	 }
        
     	if(this.PromiseState === 'rejected'){
            try{
                //获取回调函数的值
         	 	let result = onRejected(this.PromiseResult);
             	//判断
             	if(result instanceof Promise){
                 	result.then(v =>{
                     	//成功的结果为v
                     	resolve(v);
                 	},r =>{
                     	//失败的结果为r
                     	reject(r);
                 	})
             	}else{
                 	resolve(result);
             	}
            }catch(e){
                reject(e);
            }
            
     	}
        
     	if(this.PromiseState === 'pending'){
         	this.callbacks.push({
             	onResolved:onResolved,
             	onRejected:onRejected
        	})
     	}
    })   
};

这里需要注意的是,原始的promise的状态,并不影响其then结果返回的结果的状态和值。

下图很好地解释了这一整个流程。

img

以上结果都是建立在同步执行的状态下,那么接下来我们将完善异步修改then方法的返回值。

let p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('OK');
        //reject('error');
        //throw 'error';
    },1000)
});

const res = p.then(value =>{
    console.log(value);
},reason =>{
    console.log(reason);
})
console.log(res);

内置的promise会先返回一个pending状态的res,一秒钟以后打印OK,且res状态变为fulfilled,res结果的值为undifined,因为在这里回调函数未返回任何东西。

然而我们手写的promise并不会在一秒后改变res的状态和结果的值 。因为我们在处理异步状态的执行时,并没有设置promise状态为pending时有关于res结果的操作。

  • 为了便于 对pending状态的promise进行操作,我们将以函数形式保存这个回调函数,便于对保存的回调函数进行操作更改

    const self = this;
    if(this.PromiseState === 'pending'){
            this.callbacks.push({
            	//onResolved:onResolved,
                onResolved:function(){
                 	//这里不使用this.PromiseResult是因为在这个函数中,this指向callbacks。
                 	onResolved(self.PromiseResult);
                }
                onRejected:function(){
                    onRejected(self.PromiseResult);
                }
            })
    }
    
  • 接下来就是在onResolvedonRejected中对回调函数的执行结果进行判断,与同步操作一致。

    const self = this;
    if(this.PromiseState === 'pending'){
            this.callbacks.push({
                onResolve:function(){
                    try{
                        //获取回调函数执行结果
                 	 	let result = onResolved(self.PromiseResult);
                        //判断
                        if(result instanceof Promise){
                            result.then(v=>{
                                resolve(v);
                            },r =>{
                                reject(r);
                            })
                        }else{
                            resolve(result);
                        }
                    }catch(e){
                        reject(e);
                    }
                }
                
                onRejected:function(){
                     try{
                        //获取回调函数执行结果
                 	 	let result = onRejected(self.PromiseResult);
                        //判断
                        if(result instanceof Promise){
                            result.then(v=>{
                                resolve(v);
                            },r =>{
                                reject(r);
                            })
                        }else{
                            resolve(result);
                        }
                    }catch(e){
                        reject(e);
                    }
                }
            })
    }
    

    到这里,有关于同步异步的then方法结果值的实现都已经完成了,但是我们注意到,有关于“判断回调函数执行结果并改变res状态”的代码重复出现了很多次,因此,我们可以对这个该段代码进行封装。

    Promise.prototype.then = function(onResolve,onReject){
        const self = this;
        return new Promise((resolve,reject) =>{
            //封装函数
            function callback(type){
                try{
                    //获取回调函数的执行结果
                    //这里的type传递的是不同状态的promise会调用`onResolved`还是`onRejected`
                    let result = type(self.PromiseResult);
                    //判断
                    if(result instance Promise){
                        result.then(v =>{
                            resolve(v);
                        },r =>{
                            reject(r);
                        })
                    }else{
                        resolve(result);
                    }
                }catch(e){
                    reject(e);
                }
            }
            
            //调用回调函数
            if(this.PromiseState === 'fulfilled'){
                callback(onResolved);
            };
            if(this.PromiseState === 'rejected'){
                callback(onRejected);
            };
            if(this.PromiseState === 'pending'){
                //保存回调函数
                this.callbacks.push({
                    onResolved:function(){
                        callback(onResolved);
                    },
                    onRejected:function(){
                        callback(onRejected);
                    }
                })
            }
        })
    }
    

catch方法和异常穿透

catch是专门演示失败的回调函数,因此可以直接调用then方法,改变参数即可。

Promise.prototype.catch = function(onRejected){
    return this.then(undifined,onRejected);
}

异常穿透是指在进行链式调用时,只需要在最后设置失败的结果。意思就是前面所有的失败异常都可以由最终一个catch来处理。

let p = new Promise((resolve,reject)=>{
    reject('error');
})
p.then(value =>{
    console.log(111);
}).then(value =>{
    console.log(222);
}).then(value =>{
    console.log(333);
}).catch(reason =>{
    console.warn(reason);
})

然而在我们的代码中,因为没有传递reason的相关内容,所以会报错onRejected is not a function ,在第一个then方法中无法找到onRejected

因此我们需要设置:当onRejected is not a function时,需要直接抛出错误,使当前then方法返回一个失败的promise对象,那么下面的then方法也是在接收失败的promise对象后再抛出错误,逐步返回失败的promise对象一直到最后的catch做出失败的回调执行。

Promise.prototype.then = function(onResolve,onReject){
    const self = this;
    //判断
    //判断错误的回调函数是否存在,若不存在,则抛出错误,then返回一个失败的promise对象。
    //这里其实是相当于在then方法中添加了一个reason=>{throw reason}的回调。
    if(typeof onRejected !== 'function'){
        onRejected = (reason) =>{
            throw reason;
        }
    }
    return new Promise((resolve,reject) =>{
        
    })
}

除了失败对象的传递,异常穿透还可以进行成功的值的传递。意思就是,如果整个链式调用中没有错误,则原始的promise成功的结果会不断传递给then方法返回的成功的promise,成为他们的结果值。

onRejected的报错一样,因此我们也可以通过相同的判断方式,为onResolved创建一个传递值的功能。

Promise.prototype.then = function(onResolve,onReject){
    const self = this;
    if(typeof onRejected !== 'function'){
        onRejected = (reason) =>{
            throw reason;
        }
    }
    if(typeof onResolved !== 'function'){
        //这里相当于为onResolved添加了value =>{return value},将当前peomise的结果的值传递给then方法返回的promise。
        onResolved = (value) => value;
    }
    return new Promise((resolve,reject) =>{
        
    })
}

resolve的封装

接下来我们会封装一些promise的API.

首先是封装Promise.resolve

我们先分析一下这个API的作用。他会传递一个value的值,这个值是promise成功的数据或者一个promise对象。且该API会返回一个promise对象

  • 如果传入的参数是非promise类型的对象,则返回的结果为成功的promise对象。
  • 如果传入的参数为promise对象,则参数的结果决定了resolve的结果。
Promise.resolve = function(value){
    return new Promise((resolve,reject)=>{
        if(value instanceof Promise){
            value.then(v=>{
                resolve(v);
            },r=>{
                reject(r);
            })
        }else{
            resolve(value);
        }
    })
}

与then方法的callback封装类似。

reject的封装

Promise.reject方法接收一个reason参数,返回一个失败的promise对象。不管传入什么都失败;传入什么,失败的结果就是什么;

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

all方法的封装

all方法会传入一个包含有n个promise对象的数组的参数,返回一个新的promise对象。当数组中的所有promise对象都成功时,返回的结果状态为成功,成功的结果为一个包含有所有promise成功值的数组;如果有失败的promise对象,则返回结果也为失败,且失败的值为第一个改变状态的promise的值。

Promise.all = function(promises){
    return new Promise((resolve,reject) =>{
        //因为所有的promise状态为成功,返回的结果状态才能改变为成功,所以需要设置一个值来检查数组中成功状态的promise是否符合要求。
        let count = 0;
        //设置一个数组来保存成功的promise的值
        let arr[];
        //遍历
        for(let i = 0;i < promises.length;i++){
            promises[i].then(v =>{
                count++;
                arr[i] = v;
                //判断
                if(count === promises.length){
                    //修改成功状态
                    resolve(arr);
                }
            },reason =>{
                //如果有失败的,则立即返回当前失败的值
                reject(r);
            })
        }
    })
}

race方法的封装

race方法会接收一个包含有n个promise对象的数组,,返回一个新的promise,第一个完成状态改变的结果就是返回的结果。

Promise.race = function(promises){
    return new Promise((resolve,reject) =>{
        for(let i = 0; i < promises.length;i++){
            //当前promise状态改变后便立即返回结果。
            promises[i].then(v =>{
                resolve(v);
            },reason =>{
                reject(r);
            })
        }
    })
}

回调函数异步执行

promise中有一个细节就是then方法中的回调函数实际上是异步执行的。

我们可以做一个检测。

let p = new Promise((resolve,reject)=>{
    resolve('OK');
    console.log(111);
})

p.then(value =>{
    console.log(222);
})

console.log(333);
//输出顺序为111,333,222

所以可以验证,then中的回调函数是异步执行的,需要等同步代码执行结束才能运行。

因此我们需要在手写的then方法中的回调函数内部添加内容使其变为异步。目前代码中总共有四处回调函数需要修改。

//声明构造函数
function Promise(executor) {
  this.PromiseState = "pending";
  this.PromiseResult = null;
  this.callbacks = [];
  const self = this;
  //resolve函数
  function resolve(data) {
    if (self.PromiseState !== "pending") return;
    self.PromiseState = "fulfilled";
    self.PromiseResult = data;
    //添加定时器设置成为异步任务
    setTimeout(() => {
      self.callbacks.forEach((item) => {
        item.onResolved(data);
      });
    });
  }
  //reject函数
  function reject(data) {
    if (self.PromiseState !== "pending") return;
    self.PromiseState = "rejected";
    self.PromiseResult = data;
    //定时器包裹成为异步任务
    setTimeout(() => {
      self.callbacks.forEach((item) => {
        item.onRejected(data);
      });
    });
  }
  try {
    executor(resolve, reject);
  } catch (e) {
    reject(e);
  }
}

//添加then方法,返回结果为promise对象
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this;
  if (typeof onRejected !== "function") {
    onRejected = (reason) => {
      throw reason;
    };
  }
  if (typeof onResolved !== "function") {
    onResolved = (value) => value;
  }
  return new Promise((resolve, reject) => {
    function callback(type) {
      try {
        let result = type(self.PromiseResult);
        if (result instanceof Promise) {
          result.then(
            (v) => {
              resolve(v);
            },
            (r) => {
              reject(r);
            }
          );
        } else {
          resolve(result);
        }
      } catch (e) {
        reject(e);
      }
    }
      
    if (this.PromiseState === "fulfilled") {
        //添加定时器包裹成为异步任务
      setTimeout(() => {
        callback(onResolved);
      });
    }
    if (this.PromiseState === "rejected") {
        //添加定时器包裹成为异步任务
      setTimeout(() => {
        callback(onRejected);
      });
    }
    if (this.PromiseState === "pending") {
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved);
        },
        onRejected: function () {
          callback(onRejected);
        },
      });
    }
  });
};

总结

到这里,promise的手写便基本完成了。下面是整体的代码以及一些注解。

//声明构造函数
function Promise(executor) {
  //添加属性
  this.PromiseState = "pending";
  this.PromiseResult = null;
  //声明属性
  this.callbacks = [];
  //保存实例对象的this值
  const self = this; //self  _this  that

  //resolve函数
  function resolve(data) {
    //判断
    if (self.PromiseState !== "pending") return;
    //1.修改对象状态(promiseState)
    self.PromiseState = "fulfilled";
    //2.设置对象结果值(promiseResult)
    self.PromiseResult = data;
    //调用成功的回调函数
    setTimeout(() => {
      self.callbacks.forEach((item) => {
        item.onResolved(data);
      });
    });
  }
  //reject函数
  function reject(data) {
    if (self.PromiseState !== "pending") return;
    //1.修改对象状态(promiseState)
    self.PromiseState = "rejected";
    //2.设置对象结果值(promiseResult)
    self.PromiseResult = data;
    //调用失败的回调函数
    setTimeout(() => {
      self.callbacks.forEach((item) => {
        item.onRejected(data);
      });
    });
  }
  try {
    //同步调用【执行器函数】
    executor(resolve, reject);
  } catch (e) {
    //修改promise对象状态为【失败】
    reject(e);
  }
}

//添加then方法,返回结果为promise对象
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this;
  if (typeof onRejected !== "function") {
    onRejected = (reason) => {
      throw reason;
    };
  }
  if (typeof onResolved !== "function") {
    onResolved = (value) => value;
  }
  return new Promise((resolve, reject) => {
    //封装函数
    function callback(type) {
      try {
        //获取回调函数的执行结果
        let result = type(self.PromiseResult);
        //判断
        if (result instanceof Promise) {
          //如果是Promise类型的对象
          result.then(
            (v) => {
              resolve(v);
            },
            (r) => {
              reject(r);
            }
          );
        } else {
          //结果状态为【成功】
          resolve(result);
        }
      } catch (e) {
        reject(e);
      }
    }
    //调用回调函数 PromiseState
    //this指向实例对象p
    if (this.PromiseState === "fulfilled") {
      setTimeout(() => {
        callback(onResolved);
      });
    }
    if (this.PromiseState === "rejected") {
      setTimeout(() => {
        callback(onRejected);
      });
    }
    if (this.PromiseState === "pending") {
      //保存回调函数
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved);
        },
        onRejected: function () {
          callback(onRejected);
        },
      });
    }
  });
};

//catch方法
Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected);
};

//resolve方法
Promise.resolve = function (value) {
  //返回promise对象
  return new Promise((resolve, reject) => {
    if (value instanceof Promise) {
      value.then(
        (v) => {
          resolve(v);
        },
        (r) => {
          reject(r);
        }
      );
    } else {
      resolve(value);
    }
  });
};

//reject方法
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason);
  });
};

//all方法
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    let count = 0;
    let arr = [];
    //遍历
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(
        (v) => {
          //得知对象状态都是成功
          //每个promise对象都成功
          count++;
          ///当前promise对象成功的结果存入数组
          arr[i] = v;
          //判断
          if (count === promises.length) {
            //修改状态
            resolve(arr);
          }
        },
        (r) => {
          reject(r);
        }
      );
    }
  });
};

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

该篇文章记录尚硅谷Promise教程,有兴趣的同学可以深入学习一下尚硅谷Web前端Promise教程从入门到精通_哔哩哔哩_bilibili