一 揭开Promise的面纱:什么是Promise?
promise是ES6新增的一个特征,它已被列入ES6的正式规范中
Promise对象可以理解为一次执行的异步操作,使用promise对象之后可 使用一种链式调用的方式来组织代码;让代码更加的直观。也就是说,有了Promise对象,就可以将异步操作以同步的操作的流程表达出来,避免了层层嵌套的回调函数。
举个栗子:
$.ajax(url1, function (data1) {
// do something
$.ajax(url2, function (data2) {
// do something
...
})
})
复制代码
我们在回调中加入我们的后续操作,这样一层一层的嵌套,就形成了可怕的‘回调金字塔’,这种写法不便于维护,也会存在许多隐藏的问题。而Promise就是为了解决些问题产生的。
二 Promise API
1 创建一个Promise
方法一:new Promise
var promise = new Promise(function(resolve, reject) {
resolve('Hello');
})
console.log(promise); // Promise{<resolved>: "Hello"}
复制代码
方法二:直接创建
var promise = Promise.resolve('Hello');
console.log(promise); // Promise{<resolved>: "Hello"}
复制代码
2 Promise.resolve()和Promise.reject()
在介绍它们时,让我们先了解Promise的三个状态,加深我们的理解:分别是pending,fulfilled和rejected 。
pending是对象创建后的初始状态,当对象fulfill(成功)时变为fulfilled,当对象reject(失败)时变为rejected。且只能从pengding变为fulfilled或rejected ,而不能逆向或从fulfilled变为rejected、从rejected变为fulfilled。
Promise.reslove()与Promise.reject()都可直接创建一个Promsie,只是二者的状态不一样:完成与拒绝。
var p1 = Promise.resolve('Hello');
var p2 = Promise.reject('Hello');
console.log(p1); // Promise{<resolved>: "Hello"}
console.log(p2); // Promise{<rejected>: "Hello"}
复制代码
3 then()、catch()、finally()
1,then方法可以接收两个参数,且通常都是函数。第一个参数会添加到fulfill时调用的数组中,第二个参数添加到reject时调用的数组中。当promise状态fulfill时,会把resolve(value)中的value值传给调用的函数中,同理,当promise状态reject时,会把reject(reason)中的reason值传给调用的函数。 举个栗子:
var promise = new Promise(function(reslove, reject) {
setTimeout(() => {
Math.random() > 0.5 ? reslove('success') : reject('fail');
}, 1000);
})
console.log(promise);
promise.then((res) => {
console.log('success ' + res);
}, (err) => {
console.log('err ' + err);
})
复制代码
当随机数大于0.5时,状态为resove,输出为'success success'
当随机数小于0.5时,状态为reject,输出为'fail fail'
复制代码
基本用法我们知道了,那么then的返回值是什么呢?
then是有返回值的,它返回一个新的Promise(与之前任何一个Promise都不同)。然而这个Promised的行为与then中的回调函数的返回值有关
复制代码
让我们来具体看个例子:
var promise = new Promise((resolve, reject) => {
resolve('success');
})
.then((res) => console.log(res))
.then(() => {console.log('第二个then')});
// 输出为:
// success
// 第二个then
复制代码
我们发现第一个then里面我们直接打印的res,并没有通过resolve或reject改变状态,按照之前的理解这个时候的状态应该是pending,不应进入第二个then里,但是却进了,那我们手动reject一下会怎样呢?
var promise = new Promise((resolve, reject) => {
resolve('success');
})
.then((res) => Promise.reject(res))
.then((res) => {console.log('1')}, (res) => {
console.log(2);
});
// 输出为
// 2
复制代码
我们发现当我们手动reject改变状态之后,就进入到了后面then的reject函数中。
why?这里我们来简单说明下:then返回是一个新的promise,并且这个新的promise默认是接受状态,若想改变状态,我们需手动重置。
2,catch()方法:只要Promsie状态更改为reject或者抛出异常,都会进入catch方法。我们来看一下:
var promise1 = Promise.reject('Hello');
promise1.then((res) => {
console.log('success' + res);
}).catch((res) => {
console.log('catch ' + res); // catch Hello
})
复制代码
then()和catch会创建并返回一个新的promise,这个Promise可以用于实现Promsie链式流程控制。
3,finally()方法,这个方法稍微特殊些,我们直接看例子吧:
var promise = Promise.resolve('Hello');
promise.then((res) => {
console.log(res); // Hello
}).finally((res) => {
console.log('finally'); // finally
console.log(res); // undefined
})
复制代码
这里我们看到finally里res的输出为undefined,这是为什么呢,为什么没有信息呢?这就是特殊的地方:由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。