背景
最近一段时间,准备换工作的事情,在B站上看了一些模拟面试视频,说实话,很多面试官问的问题,要我说我也不确定能否回答上来。针对一些常见的问题,比如生撸Promise,我也是刚刚花了一点时间,给出我的一个答案。
非常简单,算上测试代码+注释代码+换行,总共45行代码搞定。哪怕是初学者也能看明白:
实现
// 这是使用宿主环境原生Promise接口测测试用例
// function test(p) {
// return new Promise((resolve, reject) => {
// if (p == 1) resolve();
// else reject();
// })
// }
function MyPromise(fn) {
this.resolveCallback = undefined;
this.rejectCallback = undefined;
fn(this.resolve.bind(this), this.reject.bind(this));
}
MyPromise.prototype.resolve = function() {
this.resolveCallback(true);
}
MyPromise.prototype.reject = function() {
this.rejectCallback(false);
}
MyPromise.prototype.then = function(callback) {
this.resolveCallback = callback;
return this;
}
MyPromise.prototype.catch = function(callback) {
this.rejectCallback = callback;
return this;
}
function api() {
return new MyPromise(function(resolve, reject) {
setTimeout(() => {
if (Math.random() < 0.5) resolve();
else reject();
}, 1000);
});
}
// 这是针对生撸的Promise写的一个测试用例
api().then(function(res) {
console.log(4040, res)
}).catch(function(err) {
console.log(4242, err)
})
注意点
- 针对xxx.then().catch()这种情况,此时不能执行业务代码,这里只是注册回调,并不能真正执行。
- resolve()和reject()直接调用时,此时this指向全局根作用域,因此需要通过bind来保存this作用域。
链式调用
此时,改变一下需求,需要链式调用,测试代码如下:
api()
.then(function (res) {
console.log(101, res);
return api();
})
.then(function (res) {
console.log(102, res);
return api();
})
.then(function (res) {
console.log(103, res);
return api();
})
.then(function (res) {
console.log(104, res);
return api();
})
.then(function (res) {
console.log(105, res);
})
.catch(function (err) {
console.log(106, err);
});
执行后,你会发现永远是最后一个then得到执行。原因是then多次调用之后this.resolveCallback值被覆盖了。因此,我们需要缓存每一个then里面的回调函数。在开发者调用resolve之后,遍历执行缓存的每一个函数,实现如下:
function MyPromise(fn) {
this.resolveCallbacks = [];
this.rejectCallbacks = [];
this.resolveCallback = undefined;
this.rejectCallback = undefined;
fn(this.resolve.bind(this), this.reject.bind(this));
}
MyPromise.prototype.resolve = function (result) {
this.resolveCallbacks.forEach(fn => {
let ret = fn(result);
if (ret instanceof MyPromise) {
try {
ret.resolve(result);
} catch(e) {
ret.reject(e);
}
}
});
};
MyPromise.prototype.reject = function (result) {
this.rejectCallbacks.forEach(fn => {
fn(result);
});
};
MyPromise.prototype.then = function (callback) {
this.resolveCallbacks.push(callback);
return this;
};
MyPromise.prototype.catch = function (callback) {
this.rejectCallbacks.push(callback);
return this;
};
(全文完)