目录
1. 概述
Promise 是异步编程的一种解决方案。ES6 原生提供了Promise
对象。
Promise
对象是一个代理对象,被代理的值在Promise
对象创建时可能是未知的。它允许为异步操作的成功和失败分别绑定相应的处理方法。
一个Promise
有以下几种状态:
- pending:初始状态
- fulfilled:操作成功
- rejected:操作失败
Promise
对象具有以下特点:
- 对象的状态不受外界影响。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved。
2. 基本用法
Promise
对象是一个构造函数,用来生成Promise
实例。
var promise = new Promise(function(resolve, reject){
...
})
Promise
构造函数接受一个函数作为参数,Promise
构造函数执行时立即调用该函数。该函数的两个参数分别是resolve
函数和reject
函数。
resolve
函数:将Promise
对象的状态从pending
变为fulfilled
,在异步操作成功的时候会调用,并且将异步操作的结果作为参数传递。
reject
函数:将Promise
对象状态从pending
变为rejected
,在异步操作失败时会调用,并且将异步操作报出的错误作为参数传递。
Promise
实例生成以后,可以用then
方法分别指定fulfilled
状态和rejected
状态的回调函数。
promise.then(onFulfilled[, onRejected]);
then
方法可以接受两个回调函数作为参数。第一个回调函数是Promise
对象的状态变为fulfilled
时调用,第二个回调函数是Promise
对象的状态变为rejected
时调用(可选)。
下面是一个简单的例子。
// 创建Promise实例
function promise(second) {
return new Promise((resolve, reject) => setTimeout(resolve, second, "成功!"))
}
promise(100).then(value = > console.log(value)); // “成功!“”
上面代码中,promise
方法返回一个Promise
实例,内部使用定时器模拟了一个异步任务。当过了指定时间后,Promise
实例状态变为fulfilled
,就会触发then
方法绑定的回调函数。
下面是一个异步加载图片的例子。
function imgLoad(url) {
// 返回Promise实例
return new Promise((resolve, reject) => {
// 创建XMLHttpRequest实例
var request = new XMLHttpRequest();
// 设置连接信息
request.open("GET",url);
// 返回二进制对象
request.responseType = 'blob';
request.onreadystatechange = function() { // 监听状态变化
if(request.readyState === 4 && request.status === 200) { // 通信完成
return resolve(request.response);
}else{
return reject(Error("图片加载失败!" + request.statusText))
}
}
request.onerror = function(){ // 请求失败监听
return reject(Error("请求失败!"))
}
// 发送请求
request.send();
})
}
// 执行then方法
imgLoad("url").then(((response => console.info(response)), (error => console.info(error))));
3. Promise 对象实例方法
3.1 Promise.prototype.then()
then()
方法返回一个 Promise
实例,可以为Promise
实例添加状态改变的回调函数。由于then()
方法返回一个promise
实例,所以可以进行链式调用。
语法
// 创建Promise实例
var promise = new Promise(function(resolve, reject){
...
})
// then方法参数是两个回调函数
promise.then(onFulfilled[, onRejected]);
参数
以下是传递给then()
方法的参数:
- onFulfilled:当
Promise
实例状态变为fulfilled
时调用的函数,该参数可选。 - onRejected:当
Promise
实例状态变为rejected
时调用的函数,该参数可选。
返回值
当一个 Promise
状态发生改变时,返回函数将被异步调用。具体的返回值依据以下规则返回。如果 then 中的回调函数:
- 返回了一个值,那么
then
方法返回的Promise
将会成为fulfilled
,并且将返回的值作为fulfilled
状态的回调函数的参数值。 - 没有返回任何值,那么
then
方法返回的Promise
将会成为fulfilled
,并且该fulfilled
状态的回调函数的参数值为undefined
。 - 抛出一个错误,那么
then
返回的Promise
将会成为rejected
,并且将抛出的错误作为rejected
状态的回调函数的参数值。 - 返回一个已经是
fulfilled
状态的Promise
,那么then
返回的Promise
也会成为fulfilled
,并且将那个Promise
的fulfilled
状态的回调函数的参数值作为该被返回的Promise
的fulfilled
状态回调函数的参数值。 - 返回一个已经是拒绝状态的
Promise
,那么then
返回的Promise
也会成为’rejected’,并且将那个Promise
的rejected
状态的回调函数的参数值作为该被返回的Promise
的rejected
状态回调函数的参数值。 - 返回一个
pending
状态的Promise
,那么then
返回Promise
的状态也是fulfilled
的,并且它的终态与那个Promise
的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise
变为终态时的回调函数的参数是相同的。
3.2 Promise.prototype.catch()
catch()
方法返回一个Promise
实例,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected)
相同。
语法
var promise = new Promise(function(resolve, rejected){
...
})
promise.catch(onRejected);
参数
以下是传递给catch()
方法的参数:
- onRejected:当
Promise
被rejected
时,被调用的一个函数。
返回值
一个Promise
实例。
示例
var p1 = new Promise((resolve, reject) => {
resolve('Success');
});
p1.then((value) => {
throw Error("错误");
}).catch((error) => {
console.log(error); // Error: 错误
}).then(() =>{
console.log("sucess!") // sucess!
}, () => {
console.log("error");
});
3.3 Promise.prototype.finally()
finally
方法用于指定不管 Promise
对象最后状态如何,都会执行的操作。
var promise = new Promise(function(resolve, rejected){
...
})
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
finally
方法接受一个回调函数作为参数,但是该回调函数不接受任何参数。
finally
本质上是then
方法的特例。
promise
.finally(() => {
...
});
// 等价于
promise
.then(
result => {
...
return result;
},
error => {
...
throw error;
}
);
4. Promise 对象方法
4.1 Promise.all()
Promise.all()
方法用于将多个 Promise
实例,包装成一个新的Promise
实例。
const promise = Promise.all([p1, p2, p3]);
上面代码中,Promise.all()
接受一个数组作为参数,数组成员p1
,p2
,p3
都是Promise
实例。如果不是,就会将参数转为Promise
实例,再进行处理。另外,Promise.all()
方法的参数可以不是数组,但必须具有 Iterator
接口。
promise
的状态由p1
,p2
,p3
决定,分为两种情况:
p1
,p2
,p3
的状态都变成fulfilled
,promise
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给promise
的回调函数。- 只要
p1
、p2
、p3
之中有一个被rejected
,promise
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给promise
的回调函数。
示例
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'foo');
});
Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
});
上面例子红,Promise.all
等待所有都完成(或第一个失败)时才会调用后面的回调函数。
4.2 Promise.race()
Promise.race()
方法同样是将多个 Promise
实例,包装成一个新的 Promise
实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise
实例的返回值,就传递给p
的回调函数。
Promise.race()
方法的参数与Promise.all()
方法一样,如果不是 Promise
实例,参数会转为 Promise
实例,再进一步处理。
示例
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// 两个都完成,但 p2 更快
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "three");
});
var p4 = new Promise(function(resolve, reject) {
setTimeout(reject, 500, "four");
});
Promise.race([p3, p4]).then(function(value) {
console.log(value); // "three"
// p3 更快,所以它完成了
}, function(reason) {
// 未被调用
});
var p5 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "five");
});
var p6 = new Promise(function(resolve, reject) {
setTimeout(reject, 100, "six");
});
Promise.race([p5, p6]).then(function(value) {
// 未被调用
}, function(reason) {
console.log(reason); // "six"
// p6 更快,所以它失败了
});
4.3 Promise.resolve()
Promise.resolve()
方法将现有对象转为一个Promise
实例。
const promise = Promise.resolve(12);
Promise.resolve
方法的参数分成四种情况:
- 参数是一个
Promise
实例,那么Promise.resolve
将不做任何修改、原封不动地返回这个实例。 - 参数是一个
thenable
对象,即具有then
方法的对象,Promise.resolve
方法会将这个对象转为Promise
对象,然后就立即执行thenable
对象的then
方法。 - 如果参数是一个原始值,或者是一个不具有
then
方法的对象,则Promise.resolve
方法返回一个新的Promise
对象,状态为fulfilled
。 - 不带有任何参数,直接返回一个
fulfilled
状态的Promise
对象。
示例
Promise.resolve("Success").then(function(value) {
console.log(value); // "Success"
}, function(value) {
// 不会被调用
});
Promise.resolve([1,2,3]).then(function(v) {
console.log(v[0]); // 1
});
4.4 Promise.reject()
Promise.reject()
方法返回一个带有拒绝原因的Promise
对象。
示例
Promise.reject(new Error('fail')).then(function() {
// not called
}, function(error) {
console.error(error); // Stacktrace
});
5 参考链接
本篇博文是我自己学习笔记,原文请参考:ECMAScript 6 入门,MDN网站。
如有问题,请及时指出!
欢迎沟通交流,邮箱:jidi_jidi@163.com。