要分析Promise之前,先来了解下Promise的应用场景。
先说结果:Promise非常适用于异步场景,或者其他需要状态保存的场景。
我们来看看MDN对于Promise的定义:
Promise 对象用于表示一个异步操作的最终完成(或失败),及其结果值
看看具体使用:
const promise1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
promise1.then(function(value) {
console.log(value);
});
// 300ms后输出'foo'
以上是Promise最简单的使用方式
下面主要介绍为何Promise能实现上述的效果以及更多复杂的场景。
好的,就像大部分的视频网站播放的游戏广告一样(开局一条狗,装备全靠捡),先附上流程图(盗用MDN的图)
Promise 标准解读
- 只有一个then方法,没有catch,race,all等方法
- then方法返回一个新的Promise
- Promise的初始状态为pending,可以转换为resoved或者rejected,状态一旦确定,无法更改
一步一步实现Promise
构造函数
Promise构造函数接收一个executor函数,executor函数执行完异步操作后,调用它的两个参数resolve和reject
function Promise(executor) {
var self = this;
self.status = 'pending'; // Promise 当前的状态
self.value = undefined; // Promise的值
self.onResolveCb = []; // resolve回调函数集,Promise执行完毕时可能resolve还未调用(异步),也可能存在多个回调
self.onRejectCb = []; // reject回调函数集,Promise执行完毕时可能reject还未调用(异步),也可能存在多个回调
function resolve(value) {
if (self.status === 'pending') {
self.status = 'resolved';
self.value = value;
for (var i = 0; i < self.onResolveCb.length; i++) {
self.onResolveCb[i](value);
}
}
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
for (var i = 0; i < self.onResolveCb.length; i++) {
self.onRejectCb[i](reason);
}
}
}
try {
executor(resolve, reject); // 执行executor函数,并传入相应的参数
} catch(e) {
reject(e);
}
}
上面的代码主要做了两件事:
1 定义Promise的状态及其状态值
2 通过定义的内部函数去修改由pending转换为resolved或者rejected
原型上的then方法
Promise对象上有一个then方法,这个方法主要用来注册Promise状态确定后的回调。
而且每个Promise对象都可以在其上多次调用then方法,而每次调用then返回的Promise状态取决于上一次调用then方法返回的结果,所以then不能返回this。
看看then是如何实现的
// then方法接收两个参数,onFulfilled onRejected分别为Promise成功和失败的回调
Promise.prototype.then = function(onFulfilled, onRejected) {
var self = this;
var promise2;
// 防止传入的参数不是函数,需要做以下处理
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(v) {return v};
onRejected = typeof onRejected === 'function' ? onRejected : function(r) {return r};
if (self.status === 'resolved') {
return promise2 = new Promise(function(resolve, reject) {
try {
var x = onFulfilled(self.value);
if (x instanceof Promise) { // 如果x是Promise对象,直接将它作为primise2的结果
x.then(resolve, reject);
}
resolve(x);
} catch(e) {
reject(e);
}
});
}
if (self.status === 'rejected') {
return promise2 = new Promise(function(resolve, reject) {
try {
var x = onRejected(self.reason);
if (x instanceof Promise) { // 如果x是Promise对象,直接将它作为primise2的结果
x.then(resolve, reject);
}
} catch(e) {
reject(e);
}
});
}
if (self.status === 'pending') {
return promise2 = new Promise(function(resolve, reject) {
self.onResolveCb.push(function() {
try {
var x = onFulfilled(self.value);
if (x instanceof Promise) { // 如果x是Promise对象,直接将它作为primise2的结果
x.then(resolve, reject);
}
} catch(e) {
reject(e);
}
});
self.onRejectCb.push(function() {
try {
var x = onRejected(self.reason);
if (x instanceof Promise) { // 如果x是Promise对象,直接将它作为primise2的结果
x.then(resolve, reject);
}
} catch(e) {
reject(e);
}
});
});
}
};
Promise.prototype.catch = function(onReject) {
return this.then(null, onReject);
};
以上一个Promise就已经书写完毕(race,all自行google)
好了,现在我们测试下:
1 最简单的
2 处理异步
3 输出拒绝状态的Promise
4 then链式调用
5 处理异常
至此,Promise的探究到此结束,剩余的race、all方法可以自行探索。
总结一下,Promise在解决异步方面确实好用,但是Promise也不是没有缺点,比如说性能问题,then链过长,如何停止Promise。这些问题,留给大家自行思考!