ES6的发布,解决了以前的js的大部分问题,但要说ES6中提出的哪部分内容最火?毫无疑问Promise肯定是备选之一。
那Promise是什么呢?它又解决了什么问题呢?它有什么应用和方法呢?
下面我们一一叙述。
首先我们先了解Promise解决的什么问题,然后才会对Promise有一个大概的方向,然后叙述Promise的原理,使得对Promise有个直观的理解,最后叙述Promise的方法与应用,加深对Promise的理解。最后一点会在另一篇中叙述。
Promise解决了什么问题
我们不直接阐述结论。
首先我们有一个需求,我们要实现call10这个函数,但是call10的实现依赖call9(,而call9()的实现依赖call8,......,call1的实现依赖call。如果在es6未提出之前,那么代码将会是:(这里使用es6的箭头函数优化代码)
function call() {
call1 = () => {
call2 = () => {
call3 = () => {
call4 = () => {
call6 = () => {
call7 = () => {
call8 = () => {
call9 = () => {
call10 = (val) => {
return val
}
}
}
}
}
}
}
}
}
}
看着这个代码是不是很吓人,如果是call100呢,脑补一下画面,会不会感觉很崩溃。
而上述这种代码风格被称之为回调地狱问题,确实很形象。
上面的代码如果用Promise之后呢?
我们来看一下:
let call = new Promise(function (resolve, reject) {
resolve()
})
call.then()//实现call1
.then()//实现call2
.then()//实现call3
.then()//实现call4
.then()//实现call5
.then()//实现call6
.then()//实现call7
.then()//实现call8
.then()//实现call9
.then()//实现call10
看着是不是比第一个代码更舒服,更方便。
确实Promise的提出主要是为了解决回调地狱的问题。
解决回调地狱,解决回调地狱,解决回调地狱
Promise是什么
我们先看一个Promise实例:
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
通过这个实例我们可以得到以下信息:
- Promise是一个类(构造函数)
- Promise是一个容器,里面包含一个函数,这个函数一共两个参数,分别是resolve和reject
- Promise主要是用来解决异步的任务,也就是异步回调
好,我们现在对于Promise算是有个非常基础的理解了。
Promise的三种状态
Promise
对象存在以下三种状态:
Pending(进行中)
Fulfilled(已成功)
(后面我们用resolve代替)Rejected(已失败)
这三种状态之间只存在两种转化关系,分别是:
- Pending ----> Resolve
- Pending ---->Reject
这样我们就可以得出Promise的第一个特点:
- Promise的状态一旦确定(Resolve,Reject),就无法再改变。
同时我们也应该注意一下几点:
- 如果Promise中为调用Resolve或者Reject,那它会处于Pending的状态。无法调用then函数。
- Promise内部的状态不受外界的影响。
- Promise无return函数,是通过Resolve或者Reject保存数值。
Promise源码
const [Pedding, Resolved, Rejected] = ['pedding', 'resolved', 'rejected'];
function MyPromise(fn) {
var self = this;
this.state = Pedding;
this.value = null;
this.ResolvedCallbacks = [];
this.RejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
下面我们来解析一下源码。
首先 constructor这部分内容就先不讲,有兴趣的可以去看阮大佬的es6教程。
我们知道Promise主要有三部分:
- 状态(resolve/reject)(初始状态为Pending)
- Resolve成功及内容
- Reject失败及内容
所以源码初始化就是以上三个部分的内容:
this.state = Pedding;
this.value = null;
然后分别针对Resolve和Reject作了分别的定义,并包含执行错误的情况。
if (self.state === Pedding)
上述这行if语句保证了Promise的状态转换的唯一性。