认识Promise对象

1、Promise含义

Promise 是异步编程的一种解决方案。它的最大好处是在异步执行的流程中,把执行代码和处理结果的代码分离开。promise相当于一个容器,里面保存着某个未来才会结束的事件的结果 —— 通常是一个异步操作。
Promise对象有两大特点:
(1)对象的状态不受外界的影响。
promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有promise中的异步操作才能决定当前是哪一种状态。
(2)一旦状态改变就不会再改变,任何时候都可以得到这个结果。Promise对象的状态变化只有两种可能,从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就不会再变化,这时成为resolved(已定性)。

注意 为了写作方便,本章以后resolved统一指fulfilled状态,不包含rejected状态。

2、基本用法

ES6规定,Promise对象是一个构造函数,用来生成Promise实例。

//创作一个Promise实例
const promise = new Promise(function(resolve, reject){
	if (/* 异步成功 */){
		resolve(value);
	} else {
		reject(error);
	}
});

Promise构造函数接受一个函数作为参数,该函数有两个参数resolve和reject。这两个参数也是两个函数,由JavaScript引擎提供。
resolve函数在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数在异步操作失败时调用,并将异步操作报错的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的。这两个函数都接受Promise对象传出的值作为参数。

promise.then(function(){
	//success
}, function(){
	//failure
});

Promise函数新建后会立即执行,而then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行。

let promise = new Promise(function(resolve, reject){
	console.log('立即执行Promise');
	resolve();
});
promise.then(function(){
	console.log('执行then方法的回调');
});
console.log('Hi');

//立即执行Promise
//Hi
//执行then方法的回调

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例

const P1 = new Promise(function(resolve, reject){
	setTimeout(() => reject(new Error('fail')), 3000);
});
const P2 = new Promise(function(resolve, reject){
	setTimeout(() => resolve(P1), 1000)
});
P2.then(result => console.log(result))
  .catch(error => console.log(error))
//Error: fail

上面代码P1是一个Promise,3秒后变为rejected。P2的状态在1秒后变为resolve,resolve返回的是P1。由于P2返回的是一个Promise,导致P2自己的状态无效了,P1的状态决定了P2的状态。

注意,调用resolve或reject并不会终结 Promise 的参数函数的执行。

new Promise((resolve, reject) => {
	resolve(1);
	console.log('2');
}).then(r => {
	console.log(r);
});
//2
//1

调用resolve(1)以后,后面的console.log(2)还是会执行,并首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
一般来说,调用resolve或reject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而不应该直接写在resolve或reject的后面。所以,最好在它们前面加上return语句,这样就不会有意外。

new Promise((resolve, reject) => {
	return resolve(1);
	//后面的代码将不再执行
})

3、Promise.prototype.then()

前面已经讲过then方法的用法,这边再补充一些。then方法返回的是一个新的Promise实例(不是原来的Promise实例了),因此可以采用链式写法。

new Promise((resolve, reject) => {
}).then((r) => {
}).then((r) => {
});

4、Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

const promise = new Promise(function(resolve, reject){
	throw new Error('抛错喽');
});
promise.then(function(data){
	
}).catch(function(error){
	console.log(error);
});
//Error: 抛错喽

5、Promise.prototype.finally()

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
finally方法的回调函数不接受任何参数。

Promise.then(result => {
}).then(result => {
}).catch(error => {
}).finally(() => {});

不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。

6、Promise.all()

Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。
Promise.all方法会接受一个数组作为参数,p1、p2、p3都是Promise实例。如果参数不说Promise实例,就会先调用Promise.resolve方法,讲参数转化为Promise实例。

const p = Promise.all([p1, p2, p3]);

p的状态由p1、p2、p3决定。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

var one = new Promise(function(resolve, reject){
	setTimeout(resolve, 500, 'one');
});
var two = new Promise(function(resolve, reject){
	setTimeout(resolve, 600, 'two');
});
//同时执行one和two,并在他们都完成后执行then
Promise.all([one, two]).then(function(results){
	console.log(results);
});
//["one", "two"]

7、Promise.race()

Promise.race方法同样是将多个Promise实例,包装成一个新的Promise实例。

const p = Promise.race([p1, p2, p3]);

只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给P的回调函数。

var one = new Promise(function(resolve, reject){
	setTimeout(resolve, 500, 'one');
});
var two = new Promise(function(resolve, reject){
	setTimeout(resolve, 600, 'two');
});
Promise.race([one, two]).then(function(result){
	console.log(result);
});
//one

8、Promise.resolve()

将现有对象转化为Promise对象

const promise = Promise.resolve('foo');
//等价于
new Promise(resolve => resolve('foo'));

注意 立即resolve的Promise对象,是在本轮“事件循环”(event loop)结束时,而不是在下一轮“事件循环”的开始时。

setTimeout(function(){
	console.log('three');
}, 0);
Promise.resolve().then(function(){
	console.log('two');
});
console.log('one');
//one
//two
//three

setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log(‘one’)则是立即执行,因此最先输出。

9、Promise.reject()

Promise.reject方法也会返回一个新的Promise实例,该实例的状态为rejected。

注意 Promise.reject()方法的参数,会原封不动的变为后续方法的参数,这一点与Promise.resolve方法不一致。

const thenable = {
	then(resolve,  reject){
		reject('Error');
	}
};
Promise.reject(thenable)
	.catch(e => {
		console.log(e === thenable);
});
//true

Promise.reject方法的参数是一个thenable对象,执行以后,后面catch方法的参数不是reject抛出的“Error”这个字符串,而是thenable对象。

参考资料1
参考资料2

猜你喜欢

转载自blog.csdn.net/z1324402468/article/details/85728591
今日推荐