nodejs面试时,会常常被问到promise的相关实现和原理,甚至还有现场写个Promise的实现。所以首先对Promise要有一定的了解。
Promise结构
let p = new Promise((resolve, reject) => {
// doing something
... ...
resolve(result) // 成功
//reject(errmsg) // 失败
})
.then(result => { ... }, errmsg => { ... })
.catch(error => {... })
- Promise有三种状态:pending,fulfilled,rejected
- Promise是一个类,构造函数的参数是一个函数,函数接收的参数也是2个函数(reslove函数和reject函数)
- resolve函数表示成功,传入的值会传给then方法的回调函数,reject函数表示失败
- 有个then方法,有2个参数,第一个参数是成功之后执行的回调函数,第二个参数是失败之后的执行的回调函数;且then方法在resolve或reject执行之后才会执行
- Promise支持链式调用
实现Promise
实现一个Promise类,需要以下内容:
1、状态:进行中,成功,失败;且状态转换只允许是:进行中-->成功;进行中-->失败
2、resolve和reject方法
3、then方法:参数为2个回调函数
4、执行方法:promise状态改变的方法
5、链式调用:每次then方法都返回一个新的Promise
class myPromise {
static pending = 'pending';
static fulfilled = 'fulfilled';
static rejected = 'rejected';
constructor(executor) {
this.status = myPromise.pending;//初始状态为pending
this.value = undefined; // 操作成功时返回值
this.message = undefined; // 操作失败时返回值
this.callbacks = [];
// 绑定this防止执行时this指向对象改变
executor(this._resolve.bind(this), this._reject().bind(this))
}
// 参数onFulFilled 是函数,成功时执行
// 参数onRejected是函数,失败时执行
// 不是then函数在状态改变后执行,而是then中的回调函数在状态改变后执行,所以then方法将回调当入队列中
then(onFulFilled, onRejected) {
return myPromise((nextResolve, nextRejected) => {
this._handler({
nextResolve,
nextRejected,
onFulFilled,
onRejected
})
})
}
_resolve(value) {
this.value = value;
this.status = myPromise.fulfilled;// 状态设置为成功
// 通知事件执行
this.callbacks.forEach((cb) => { this._handler(cb) })
}
_reject(message) {
this.message = message;
this.status = myPromise.rejected; // 状态设置为失败
// 通知事件执行
this.callbacks.forEach((cb) => { this._handler(cb) })
}
_handler(callback) {
const { onFulFilled, onRejected ,nextResolve, nextReject} = callback;
if (this.status === myPromise.pending) {
this.callbacks.push(callback);
return;
}
if (this.status === myPromise.fulfilled) {
// 传入存储的值
// 未传入onFulfilled时,将undefined传入
const nextValue = onFulfilled ? onFulfilled(this.value) : undefined;
nextResolve(nextValue);
return;
}
if (this.status === myPromise.rejected) {
// 传入存储的错误信息
// 同样的处理
const nextMessage = onRejected ? onRejected(this.message) : undefined;
nextResolve(nextMessage);
}
}
}
面试题
1、题目1:Promise中then第二个参数与catch的区别
- 如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到
- then的第二个参数和catch捕获错误信息的时候会就近原则,如果是promise内部报错,reject抛出错误后,then的第二个参数和catch方法都存在的情况下,只有then的第二个参数能捕获到,如果then的第二个参数不存在,则catch方法会捕获到。
2、使用Promise方式实现一个睡眠2秒的机制
init();
async function init(){
var temp = await sleepFunc(2000);
console.log('sleep 2s 后输出');
}
// Promise方式实现sleep方法
function sleepFunc(mitime) {
return new Promise((resolve) =>{
setTimeout(resovle, mitime)
})
}