1、描述
什么是 Promise?
-
Promise 是一个函数也是一个对象,它代表了一个异步操作的最终完成或者失败。
这么简单?没错,就是这么简单,Promise 没你想的那么难。
2、三种状态
一个 Promise 必然处于以下几种状态之一:
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled): 意味着操作成功完成。
- 已拒绝(rejected): 意味着操作失败。
注意:状态只能从
pending到fulfilled或者rejected,反之不行,也就是说,一旦状态发生改变就不能再改变了。
3、最基本的 Promise 例子
const p = new Promise((resolve, reject) => {
// resolve 后状态就从 pending 变为 fulfilled
resolve('成功的结果');
// reject('失败的结果')(如果 reject ,那么状态就从 pending 变为 rejected )
});
4、then() 和 catch() 方法
看下面的例子:
const p = new Promise((resolve, reject) => {
resolve('成功的结果');
})
.then(res => {
console.log(res); //成功的结果
})
.catch(rej => {
console.log(rej);
});
我们能从上面这段代码读到什么信息呢?
- 首先,
resolve后状态就从pending变为fulfilled;- 状态变成
fulfilled后就会执行then方法;then方法中的参数res就是resolve传来的成功的结果,如果resolve时不传参数,那么then方法中的res就是undefined。
再看这个例子:
const p = new Promise((resolve, reject) => {
resolve('成功的结果');
})
.then(res => {
console.log(res); // 成功的结果
return new Promise((resolve, reject) => {
resolve('成功了');
});
})
.catch(rej => {
console.log(rej);
})
.then(res => {
console.log(res);
});
注意:此时我在第一个
then方法中又返回了一个Promise。
输出结果为:
成功的结果
成功了
为什么?
- 在第一个
then中 返回一个Promise,这个Promise调用了resolve()方法;- 此时状态变为了
fulfilled,那么后面的.catch()肯定不会执行,跳过它,往下走;- 遇到了
.then(),fulfilled状态对应的就是.then(),所以肯定会执行then(),又因为resolve()时带了参数,所以res参数为成功了。
5、默认返回 undefined
看下面的例子:
const p = new Promise((resolve, reject) => {
resolve('成功的结果');
})
.then(res => {
console.log(res);
new Promise((resolve, reject) => {
resolve('成功了');
});
})
.catch(rej => {
console.log(rej);
})
.then(res => {
console.log(res);
});
输出结果为:
成功的结果
undefined
为什么?
- 首先在第一个
then里面先打印 '成功的结果',这个没什么好说的;- 然后代码往下执行,注意,此时
new Promise前面并没有加return,也就是说第一个then里隐藏了一段代码:return undefined;- 此时状态变成了
fulfilled,跳过catch(),执行then(),输出undefined。
6、new Promise() 的其他写法
思考一下,有时候我们 new Promise() 的目的是什么?是不是只是为了给后面的 .then 或者 .catch 传递参数,那既然你只是想把返回结果作为参数传过去,你就可以写成下面这样:
const p = new Promise((resolve, reject) => {
resolve('成功的结果');
})
.then(res => {
return Promise.resolve('成功了');
})
.then(res => {
console.log(res); //成功了
})
.catch(rej => {
console.log(rej);
});
设计师看了,觉得还不够简单,于是他干脆直接返回一个字符串:
const p = new Promise((resolve, reject) => {
resolve('成功的结果');
})
.then(res => {
return '我是 then 里的 res 哦';
})
.then(res => {
console.log(res); //我是 then 里的 res 哦
})
.catch(rej => {
console.log(rej);
});
注意:如果直接 return 一个字符串或者数字,JS 引擎就会把它包装成
Promise对象,并且自动执行Promise.resolve(),所以会走 then 方法。
7、链式调用
既然 then() 和 catch() 方法都返回一个 Promise,那么我就可以进行如下的操作:
const p = new Promise((resolve, reject) => {
resolve('成功的结果');
})
.then(res => {
return new Promise((res, rej) => {
res('我是第一次结果');
});
})
.then(res => {
console.log(res);
return Promise.resolve('我是第二次结果');
})
.then(res => {
console.log(res);
return Promise.reject('我是第三次结果');
})
.catch(rej => {
console.log(rej);
});
相信聪明的小伙伴已经看出来了,这就是传说中的解决回调地狱的法宝——链式调用,通过这种 .then() 的方式非常优雅地解决了以前那种函数嵌套,且造成代码不易读以及维护难的问题,感谢Promise!
8、总结
-
Promise作为构造函数时,接收一个函数作为参数,这个函数的参数又接收两个函数作为参数,分别为resolve和reject。 -
Promise作为对象时,有静态方法,比如Promise.resolve(),Promise.reject(),其中resolve()对应.then(),rejected()对应.catch()。 -
Promise.prototype.then(),Promise.prototype.catch(),这两个方法都会返回一个Promise。