• 作者:老汪软件技巧
  • 发表时间:2024-08-25 04:01
  • 浏览量:

前言

各位小伙伴秋招已经开始了,大家八股准备的怎么样了呀?算法题刷了几遍了呀?今天,蘑菇头将带着大家来手写一道面试中常考的家伙---Promise。准备好瓜子小板凳,准备出发。

正文

Promise相信大家不会很陌生,我们经常用它来将异步代码转为同步代码,这里就不做过多介绍了。

new Promise((resolve, reject) => {
	setTimeOut(()=>{
		resolve(1);
	},1000)
}).then(res => {
    console.log(res);
}).catch(err => {
    console.log(err);
})

Promise

首先我们使用es6的语法定义一个MyPromise类,Promise他会接受一个回调,回调里面有两个参数分别是resolve和reject,我们用executor来表示这个回调,在构造函数里面触发这个回调,参数为resolve,reject。

class MyPromise{
    constructor(executor) {
        const resolve = () => {}
        const reject = () => {}
        executor(resolve,reject);
    }
}

Promise有三种状态,分别是pending,fulfilled,rejected。而且他们的状态一经更改就无法变更,并且.then触发之后.catch就不能触发,所以我们在构造函数里面定义一个状态state表示当前Promise的状态,默认是pending。

Promise的resolve函数和reject函数会接受一个参数用于.then或者.catch里面的形参,所以我们定义一个value表示这个参数。

Promise是当我们resolve之后.then里的回调才会触发,状态才会发生变更,而且Promise后面可以接多个.then或者.catch,所以我们需要一个数组将.then或者.catch里面回调函数存起来,一起调用,并且在resolve函数里面我们肯定要将state的状态修改,除此之外要将resolve的参数赋值给value存储起来以便后续使用。

class MyPromise{
    constructor(executor) {
        this.status = 'pending';//定义Promise状态
        this.value = undefined;//用于将resolve中的值存起来
        this.onResolvedCallbacks = [];//用来存.then中的回调
        this.onRejectedCallbacks = [];//用来存.catch中的回调
        const resolve = (val) => {
            if(this.status === 'pending') {
                this.status = 'resolved';
                this.value = val;
                this.onResolvedCallbacks.forEach(fn => fn());
            }
        }
        const reject = (val) => {
            if(this.status === 'pending') {
                this.status = 'rejected';
                this.value = val;
                this.onRejectedCallbacks.forEach(fn => fn());
            }
        }
        executor(resolve,reject);
    }
}

Promise.then

我们只需要记住一点,.then里面的回调是在resolve中触发的。所以我们需要在.then里面收集这些回调函数,也就是push进我们的数组里面去。

Promise的.then它其实接收两个回调,一个是resolve之后才会触发的回调,一个是reject之后才会触发的回调,这是以前的写法,只不过后面官方将后面的那个回调拎出来写成了.catch。所以我们在then方法里面写上这两个回调。

手写promiss_电脑输入法手写手写连笔王驱动_

并且规定then方法里面只能传回调函数,不允许传其他数据类型,所以在此之前做一些参数类型判断。

then(onFulfilled,onRejected) {
	if (onFulfilled && typeof onFulfilled !== 'function' || onRejected && typeof onRejected !== 'function') {
            throw new Error('then必须接受一个函数');
        }
	...
}

由于then方法后面还可以接.then或者.catch,所以它肯定return出来了一个新的Promise。

then(onFulfilled,onRejected) {
	if (onFulfilled && typeof onFulfilled !== 'function' || onRejected && typeof onRejected !== 'function') {
            throw new Error('then必须接受一个函数');
        }
        return new MyPromise((resolve,reject)=>{
            
        })
}

当我们的代码写成这样时,then中的回调就不需要放进数组中再到resolve中调用了。

new Promise((resolve,reject)=>{
	resolve(1)
}).then((res)=>{
	console.log(res)
})

也就是说当.then上一个哥们的Promise状态为Fulfilled时,我们直接调用这个回调函数。由于我们无法真实模拟异步,所以这里使用setTimeout实现。同理,第二个回调函数也一样,当.then上一哥们的Promise状态为rejected时,我们也是直接调用这个函数。

then(onFulfilled, onRejected ) {
        if (onFulfilled && typeof onFulfilled !== 'function' || onRejected && typeof onRejected !== 'function') {
            throw new Error('then必须接受一个函数');
        }
        return new MyPromise((resolve, reject) => {
            if (this.state === 'fulfilled') {
                setTimeout(() => {
                    try {
                        const result = onFulfilled(this.value);//调用这个回调函数
                        resolve(result);
                    } catch (error) {
                        reject(error)
                    }
                })
            }
            if(this.state = 'rejected'){
                setTimeout(()=>{
                    try {
                        const x = onRejected(this.value);
                        resolve(x);
                    } catch (error) {
                        reject(error);
                    }
                })
            }
        }
}

当上一个哥们状态为pending时,也就是正常的异步情况了。我们需要将回调函数放进我们准备好的数组中,然后在resolve中执行完这些回调函数。

then(onFulfilled, onRejected ) {
        if (onFulfilled && typeof onFulfilled !== 'function' || onRejected && typeof onRejected !== 'function') {
            throw new Error('then必须接受一个函数');
        }
        return new MyPromise((resolve, reject) => {
            if (this.state === 'fulfilled') {
                setTimeout(() => {
                    try {
                        const result = onFulfilled(this.value);//调用这个回调函数
                        resolve(result);
                    } catch (error) {
                        reject(error)
                    }
                })
            }
            if(this.state = 'rejected'){
                setTimeout(()=>{
                    try {
                        const x = onRejected(this.value);
                        resolve(x);
                    } catch (error) {
                        reject(error);
                    }
                })
            }
            if(this.state === 'pending'){
                this.onFulfilledCallbacks.push((val)=>{
                    setTimeout(()=>{
                        onFulfilled(val);
                    })
                })
                this.onRejectedCallbacks.push((val)=>{
                    setTimeout(()=>{
                        onRejected(val);
                    })
                })
            }
        }
}

Promise.all

promise.all方法接收一个Promise数组,返回一个Promise。遍历这个数组的Promise状态,当全部状态为Fulfilled时,返回成功的Promise,在这个成功的Promise的.then方法里面可以拿到所有的Promise resolve出来的结果,只要有一个是rejected,返回rejected,那么我要怎么判断一个Promise的状态呢?我们可以利用.then方法知道,只要第一个回调触发了,说明是成功的状态。

static all(promises) { //promises是一个promise数组,当所有的promise都成功时,才成功,只要有一个失败,就失败
        return new MyPromise((resolve, reject) => {
            let count = 0;
            let res = [] //用一个数组装每个Promise resolve出来的结果
            promises.forEach(promise => {
                promise.then((val) => {
                    res[count] = val;
                    count++;
                    if (count === promises.length) {
                        resolve(res);
                    }
                }, () => {
                    reject();
                })
            });
        })
    }

Promise.race

和Promise.all类似,也是传入一个Promise数组,返回一个Promise与最先状态确定的Promise结果一致,所以很好写。

static race(promises){
	return new MyPromise((resolve,reject)=>{
		promises.forEach(promise=>{
			promise.then((val)=>{
				resolve(val);
			},()=>{
				reject();
			})
		})
	})
}