ECMAScript 6 之Promise 对象

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,并且将那个 Promisefulfilled状态的回调函数的参数值作为该被返回的Promisefulfilled状态回调函数的参数值。
  • 返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为’rejected’,并且将那个 Promiserejected状态的回调函数的参数值作为该被返回的Promiserejected状态回调函数的参数值。
  • 返回一个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:当Promiserejected时,被调用的一个函数。

返回值
一个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()接受一个数组作为参数,数组成员p1p2p3都是Promise实例。如果不是,就会将参数转为Promise实例,再进行处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口。

promise的状态由p1p2p3决定,分为两种情况:

  • p1p2p3的状态都变成fulfilledpromise的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给promise的回调函数。
  • 只要p1p2p3之中有一个被rejectedpromise的状态就变成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]);

上面代码中,只要p1p2p3之中有一个实例率先改变状态,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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值