实现Promise

面试被摁在地上摩擦,面试官:手写一个promise吧。我:我不太了解会用不会写。。。。。

找到痛点,实现一下吧。。。

promise的使用

const text = new Promise((resolve, reject) => {
  resolve("我好菜");
});

text.then((res) => {
    console.log(res)
}, (err) => {
    console.log(err)
});
复制代码

promise的实现

首先通过上面的使用方法所知,promise是一个类,那我们就用class来定义它


class TestPromise {
    constructor() {}
} 

复制代码

总所周知,promise是有三个状态的,那我们先定义一下,而且要给他一个初始的状态,

const RESOLVE = 'resolve',
const REJECT = 'reject',
const PENDING = 'pending',


class TestPromise {
    status = PENDING;
    constructor() {}
}
复制代码

promise 会接收一个函数作为参数,并且传入后会立即执行

constructor(excution) {
        excution()
    }
复制代码

函数会带有两个参数resolve,reject,所以我们要定义一下

const RESOLVE = 'resolve',
const REJECT = 'reject',
const PENDING = 'pending',


class TestPromise {
    status = PENDING;
    result = undefined;
    reason = undefined;
    constructor(excution) {
        // 调用resolve和reject的时候要传参, 参数默认为undefined
        const resolve = (result) => {
            
        }
        const reject = (reason) => {

        } 
        excution(resolve, reject)
    }
}

复制代码

我们知道promise的状态一经改变是无法更改的,所以在进入对应函数的时候要更改相应的状态

const resolve = (result) => {
    if(this.status === PENDING) {
        this.result = result;
        this.status = RESOLVE;
    }
}
const reject = (reason) => {
    if(this.status === PENDING) {
        this.result = reason;
        this.status = REJECT;
    }
} 
复制代码

然后看下我们调用的then方法,先在代码中给他定义出来

// 调用then方法, 接收两个方法!
then(onResolved, onReject) {

}
复制代码

传入的方法是需要运行的, 第一个参数和第二个参数分别为不同状态的时候去运行

// 调用then方法, 接收两个方法!
then(onResolved, onReject) {
    // 传入的方法需要运行,根据不同的状态运行不同的方法
    if (this.status === RESOLVE) {
        onResolved(this.result)
    }
    if (this.status === REJECT) {
        onReject(this.result)
    }
}
复制代码

初版差不多出来了, 长这个样子

const RESOLVE = 'resolve',
const REJECT = 'reject',
const PENDING = 'pending',


class TestPromise {
    status = PENDING;
    result = undefined;
    reason = undefined;
    constructor(excution) {
        // 调用resolve和reject的时候要传参, 参数默认为undefined
        const resolve = (result) => {
            if(this.status === PENDING) {
                this.result = result;
                this.status = RESOLVE;
            }
        }
        const reject = (reason) => {
            if(this.status === PENDING) {
                this.result = reason;
                this.status = REJECT;
            }
        } 
        excution(resolve, reject);
    }
    // 调用then方法, 接收两个方法!
    then(onResolved, onReject) {
        // 传入的方法需要运行,根据不同的状态运行不同的方法
        if (this.status === RESOLVE) {
            onResolved(this.result)
        }
        if (this.status === REJECT) {
            onReject(this.result)
        }
    }
}
复制代码

验证一下

const newTest = new TestPromise((resolve, reject) => {
    resolve('啦啦啦啦啦');
});
const text = new Promise((resolve, reject) => {
    resolve("我好菜");
});

text.then((res) => {
    console.log(res)
}, (err) => {
    console.log(err)
});

newTest.then((res) => {
    console.log(res);
}, (err) => {console.log(err)})
复制代码

image.png

打印结果是出来了 但是感觉好像有点问题, 我的promise好像不是异步的。。。。搞一下,修改then中的方法

then(onResolved, onReject) {
    // 传入的方法需要运行,根据不同的状态运行不同的方法
    if (this.status === RESOLVE) {
        setTimeout(() => {
            onResolved(this.result)
        }, 0)
    }
    if (this.status === REJECT) {
        setTimeout(() => {
            onReject(this.result)
        })
    }
}
复制代码

image.png
ok! 实现了!由于原生的promise是v8引擎提供的微服务,我们无法实现v8引擎的服务,所以这里用setTimeout来实现异步

异步调用

现在我们已经实现了一个简单的promise,但是我们传入一个异步的操作会发生什么呢 试一下

const newTest = new TestPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('啦啦啦啦啦');
    }, 1000)
    
});

newTest.then((res) => {
    console.log(res);
}, (err) => {console.log(err)})
复制代码

image.png
可以看到控制台并没有结果返回

因为promise在执行then方法的时候,当前的promise并没有成功,一直处于pending状态中,所以如果调用then方法时,状态是pending,我们需要先将成功和失败的回调分别存放起来,在异步任务执行时触发resolve或者reject,依次调用成功和失败的回调

改进下代码

const RESOLVE = 'resolve';
const REJECT = 'reject';
const PENDING = 'pending';


class TestPromise {
    status = PENDING;
    result = undefined;
    reason = undefined;
    // 新增存放成功回调的数组
    onResolveCallbackArr = [];
    // 新增存放失败回调的数组
    onRejectCallbackArr = []
    constructor(excution) {
        // 调用resolve和reject的时候要传参, 参数默认为undefined
        const resolve = (result) => {
            if(this.status === PENDING) {
                this.result = result;
                this.status = RESOLVE;
                // 遍历数组执行操作
                this.onResolveCallbackArr.forEach(fn => fn());
            }
        }
        const reject = (reason) => {
            if(this.status === PENDING) {
                this.result = reason;
                this.status = REJECT;
                // 遍历数据执行操作
                this.onRejectCallbackArr.forEach(fn => fn());
            }
        } 
        excution(resolve, reject);
        
    }
    // 调用then方法, 接收两个方法!
    then(onResolved, onReject) {




        // 传入的方法需要运行,根据不同的状态运行不同的方法
        if (this.status === RESOLVE) {
            setTimeout(() => {
                onResolved(this.result)
            }, 0)
        }
        if (this.status === REJECT) {
            setTimeout(() => {
                onReject(this.result)
            }, 0)
        }
        if (this.status === PENDING) {
            // 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
            this.onResolveCallbackArr.push(() => {
                setTimeout(() => {
                    onResolved(this.result)
                }, 0)
            });
            this.onRejectCallbackArr.push(() => {
                setTimeout(() => {
                    onReject(this.result)
                }, 0)
            })
        }
    }
}

const newTest = new TestPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('啦啦啦啦啦');
    }, 1000)
    
});

newTest.then((res) => {
    console.log(res);
}, (err) => {console.log(err)})
复制代码

image.png

这样,异步的方式就完成了。

我们是通过使用发布订阅模式来完成异步的调用功能,发布订阅模式就是收集依赖 -> 触发通知 -> 取出依赖执行的这样一个过程。

链式调用

promise是可以支持链式调用的 所以我们的.then 每次返回都需要是一个promise,搞一下

then(onResolved, onReject) {
    // 建立一个promise
    let promiseTwo = new TestPromise((resove, reject) => {
        // 传入的方法需要运行,根据不同的状态运行不同的方法
        if (this.status === RESOLVE) {
            setTimeout(() => {
                onResolved(this.result)
            }, 0)
        }
        if (this.status === REJECT) {
            setTimeout(() => {
                onReject(this.result)
            }, 0)
        }
        if (this.status === PENDING) {
            // 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
            this.onResolveCallbackArr.push(() => {
                setTimeout(() => {
                    onResolved(this.result)
                }, 0)
            });
            this.onRejectCallbackArr.push(() => {
                setTimeout(() => {
                    onReject(this.result)
                }, 0)
            })
        }
    })
    // 返回一个promise
    return promiseTwo;
}

复制代码

然后测试下。。

const newTest = new TestPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('啦啦啦啦啦');
    }, 1000)
});

newTest.then((res) => {
    console.log(res);
}, (err) => {console.log(err)}).then((res) => {
    console.log(res, '哈哈哈哈')
}, (err) => {console.log(err)})
复制代码

image.png

链式调用的第二个没有打印出来,虽然我们已经return了一个promise 但是 promise 里的resolve没有触发。。。。 那我们就写个方法让他去触发这个事件

const RESOLVE = 'resolve';
const REJECT = 'reject';
const PENDING = 'pending';

const hendlePromise = (result, newPromise, resolve, reject) => {
    //  结果等于自身没有意义
    if (result === newPromise) {
        throw new Error('can not return oneself')
    }
    // 判断是不是一个Promise是的话要处理  不是的话直接返回值
    if ((typeof result === 'object' && typeof result !== null) || typeof result === 'function') {
        // 看看有么有then方法
        const then = result.then;
        // 入果有then方法,并且是个函数的话,我们就认为他是个promise,
        if (typeof then === 'function') {
            then.call(result, (r) => {
                hendlePromise(r, newPromise, resolve, reject)
            }, (e) => {
                reject(e)
            })
        } else {
            resolve(result);
        }
    } else {
        resolve(result)
    }
}

class TestPromise {
    status = PENDING;
    result = undefined;
    reason = undefined;
    // 新增存放成功回调的数组
    onResolveCallbackArr = [];
    // 新增存放失败回调的数组
    onRejectCallbackArr = []
    constructor(excution) {
        // 调用resolve和reject的时候要传参, 参数默认为undefined
        const resolve = (result) => {
            if(this.status === PENDING) {
                this.result = result;
                this.status = RESOLVE;
                // 遍历数组执行操作
                this.onResolveCallbackArr.forEach(fn => fn());
            }
        }
        const reject = (reason) => {
            if(this.status === PENDING) {
                this.result = reason;
                this.status = REJECT;
                // 遍历数据执行操作
                this.onRejectCallbackArr.forEach(fn => fn());
            }
        } 
        excution(resolve, reject);
    }
    // 调用then方法, 接收两个方法!
    then(onResolved, onReject) {
        // 建立一个promise
        let promiseTwo = new TestPromise((resove, reject) => {
            // 传入的方法需要运行,根据不同的状态运行不同的方法
            if (this.status === RESOLVE) {
                setTimeout(() => {
                   const t = onResolved(this.result)
                   hendlePromise(t, promiseTwo, resove, reject)
                }, 0)
            }
            if (this.status === REJECT) {
                setTimeout(() => {
                    const t = onReject(this.result)
                    hendlePromise(t, promiseTwo, resove, reject)
                }, 0)
            }
            if (this.status === PENDING) {
                // 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
                this.onResolveCallbackArr.push(() => {
                    setTimeout(() => {
                        const t = onResolved(this.result)
                        hendlePromise(t, promiseTwo, resove, reject)
                    }, 0)
                });
                this.onRejectCallbackArr.push(() => {
                    setTimeout(() => {
                        const t = onReject(this.result)
                        hendlePromise(t, promiseTwo, resove, reject)
                    }, 0)
                })
            }
        })
        // 返回一个promise
        return promiseTwo;
    }
}

const newTest = new TestPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('啦啦啦啦啦');
    }, 1000)
});

newTest.then((res) => {
    console.log(res);
    return '完成'
}, (err) => {console.log(err)}).then((res) => {
    console.log(res, '哈哈哈哈')
}, (err) => {console.log(err)})
复制代码

看下运行结果

image.png

剩下我们就需要在代码中新增try catch方法为了防止输入出错–看下完整的代码

const RESOLVE = 'resolve';
const REJECT = 'reject';
const PENDING = 'pending';

const hendlePromise = (result, newPromise, resolve, reject) => {
    //  结果等于自身没有意义
    if (result === newPromise) {
        throw new Error('can not return oneself')
    }

    // 新增lock属性,保证状态只更改一次
    let lock;

    // 判断是不是一个Promise是的话要处理  不是的话直接返回值
    if ((typeof result === 'object' && typeof result !== null) || typeof result === 'function') {
        try {
            // 看看有么有then方法
            const then = result.then;
            // 入果有then方法,并且是个函数的话,我们就认为他是个promise,
            if (typeof then === 'function') {
                then.call(result, (r) => {
                    if (lock) return;
                    lock = true;
                    hendlePromise(r, newPromise, resolve, reject)
                }, (e) => {
                    if (lock) return;
                    lock = true;
                    reject(e)
                })
            } else {
                resolve(result);
            }
        } catch (error) {
            if (lock) return;
            lock = true;
            reject(error)
        }
    } else {
        resolve(result)
    }
}

class TestPromise {
    status = PENDING;
    result = undefined;
    reason = undefined;
    // 新增存放成功回调的数组
    onResolveCallbackArr = [];
    // 新增存放失败回调的数组
    onRejectCallbackArr = []
    constructor(excution) {
        // 调用resolve和reject的时候要传参, 参数默认为undefined
        const resolve = (result) => {
            if(this.status === PENDING) {
                this.result = result;
                this.status = RESOLVE;
                // 遍历数组执行操作
                this.onResolveCallbackArr.forEach(fn => fn());
            }
        }
        const reject = (reason) => {
            if(this.status === PENDING) {
                this.result = reason;
                this.status = REJECT;
                // 遍历数据执行操作
                this.onRejectCallbackArr.forEach(fn => fn());
            }
        } 
        try {
            excution(resolve, reject);
          } catch (error) {
            reject(error)
          }
        
    }
    // 调用then方法, 接收两个方法!
    then(onResolved, onReject) {
        // 建立一个promise
        let promiseTwo = new TestPromise((resove, reject) => {
            // 传入的方法需要运行,根据不同的状态运行不同的方法
            if (this.status === RESOLVE) {
                setTimeout(() => {
                    try {
                        const t = onResolved(this.result)
                        hendlePromise(t, promiseTwo, resove, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            }
            if (this.status === REJECT) {
                setTimeout(() => {
                    try {
                        const t = onReject(this.result)
                        hendlePromise(t, promiseTwo, resove, reject)
                    } catch (error) {
                        reject(error)
                    }
                    
                }, 0)
            }
            if (this.status === PENDING) {
                // 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
                this.onResolveCallbackArr.push(() => {
                    setTimeout(() => {
                        try {
                            const t = onResolved(this.result)
                            hendlePromise(t, promiseTwo, resove, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                });
                this.onRejectCallbackArr.push(() => {
                    setTimeout(() => {
                        try {
                            const t = onReject(this.result)
                            hendlePromise(t, promiseTwo, resove, reject)
                        } catch (error) {
                            reject(error)
                        }
                        
                    }, 0)
                })
            }
        })
        // 返回一个promise
        return promiseTwo;
    }
}

const newTest = new TestPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('啦啦啦啦啦');
    }, 1000)
});

newTest.then((res) => {
    console.log(res);
    return '完成'
}, (err) => {console.log(err)}).then((res) => {
    console.log(res, '哈哈哈哈')
}, (err) => {console.log(err)})
复制代码

promiseAPI

catch

catch(errCallback) {
    return this.then(null, errCallback)
}
复制代码

resolve

static resolve(data) {
        return new TestPromise((resolve, reject) => {
            if (data instanceof TestPromise) {
                return data.then(resolve, reject)
            }
            if (this.status === PENDING) {
                this.status = RESOLVE;
                this.reason = data;
                this.onResolveCallbackArr.forEach(fn => fn())
            }
            resolve(data)
        })
    }
复制代码

reject

static reject(reason){
    return new TestPromise((resolve,reject)=>{
      reject(reason);
    })
}
复制代码

all

static all(values) {
        return new TestPromise((resolve, reject) => {
            let resultArr = [];
            let orderIndex = 0;
            const processResultByKey = (value, index) => {
                resultArr[index] = value;
                if (++orderIndex === values.length) {
                    resolve(resultArr)
                }
            }
            for (let i = 0; i < values.length; i++) {
                let value = values[i];
                if (value && typeof value.then === 'function') {
                  value.then((value) => {
                    processResultByKey(value, i);
                  }, reject);
                } else {
                  processResultByKey(value, i);
                }
            }
        })
    }
复制代码

race

static rece(values) {
    return new TestPromise((resove, reject) => {
        values.forEach((item) => {
            if (item && typeof item.then === 'function') {
                item.then(resove, reject)
            } else {
                resove(item)
            }
        })
    })
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享