前言
JS是单线程的。有异步编程需求时,我们通常使用:
- 回调函数
- 事件监听
- 订阅/发布
- Promise
本文介绍Promise。Promise是一个规范,最早在社区中被提出和实现,使得链式回调的代码更加优雅。后来ES6提供了Promise对象,把其写进语言规范之中。不同的平台也有自己的实现,如Node的q模块和co,Es7的async、await等等。当然,也可以自己实现一个Promise库。
规范
Promise是一个对象或函数,必须含有then方法,提供onFulfilled和onRejected两个入参。Promise是异步的,执行成功时调用onFulfilled,返回终值(eventual
value);失败调用onRejected,返回据因(reason)。
Promise.then(onFulfilled, onRejected)
一个Promise必定处于三种状态的其中一种:等待(Pending)、完成(Fulfilled)和失败(Rejected)。Pending可以转化成其余两种状态,而其余两种状态不能迁移至其他任何状态。如下图:
边界情况请参考Promise
A+规范,这里不再啰嗦。在规范中,一个Promise库还需要提供resolve、reject、all等方法,都很好理解,关键是看怎么实现,这里也不展开介绍。
实践
下面布置一道题目:实现一个符合Promise A+规范的Promise库,只需实现then方法,半小时内完成。参考答案如下:
let P = function(executor) {
let self = this;
self.status = 'pending'; //状态
self.value = undefined; //终值
self.reason = undefined; //据因
self.resolveCB = []; //成功回调
self.rejectCB = []; //失败回调
// 执行成功
function resolve (value) {
if (self.status == 'pending') {
self.status = 'fulfilled';
self.value = value;
self.resolveCB.map((cb)=>{
cb(self.value);
})
}
}
// 执行出错
function reject (reason) {
if (self.status == 'pending') {
self.status = 'rejected';
self.reason = reason;
self.rejectCB.map((cb)=>{
cb(self.reason);
})
}
}
try {
executor(resolve, reject);
} catch(e) {
reject(e);
}
}
// 实现then方法
P.prototype.then = function(onFulfilled, onRejected) {
let self = this;
let then;
if (self.status == 'fulfilled') {
return then = new P((resolve, reject)=>{
try {
let value = onFulfilled(self.value);
resolve(value);
} catch(e) {
reject(e);
}
});
}
if (self.status == 'rejected') {
return then = new P((resolve, reject)=>{
try {
let reason = onRejected(self.reason);
resolve(reason);
} catch(e) {
reject(e);
}
});
}
if (self.status == 'pending') {
then = new P((resolve, reject)=>{
self.resolveCB.push(function(){
try {
let value = onFulfilled(self.value);
resolve(value);
} catch(e) {
reject(e);
}
});
self.rejectCB.push(function(){
try {
let reason = onRejected(self.reason);
resolve(reason);
} catch(e) {
reject(e);
}
});
});
return then;
}
}
module.exports = P;
这是某大厂面试时遇到的上机题。参考答案只实现了then的链式调用,规范中的其他内容一概没有,也没有考虑边界问题,请勿在生产环境中使用。
本文未经许可禁止转载,如需转载关注微信公众号【工程师加一】并留言。