Promise使用小记

ES6 Promise使用小记

Posted by XYH on May 14, 2019

记录ES6中Promise的使用。

ES6的Promise对象使用小记。

在使用axios中,经常看到 Promise 对象,本文做个小记录。

Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值,本质上,Promise 是一个绑定了回调的对象,而不是将回调传进函数内部。

语法

1
new Promise( function(resolve, reject) {...} /* executor */  );

参数说明: executor 是带有 resolvereject 两个参数的函数 。Promise 构造函数执行时立即调用 executor 函数, resolvereject 两个函数作为参数传递给 executor(executor 函数在 Promise 构造函数返回所建 promise 实例对象前被调用)。resolvereject 函数被调用时,分别将 promise的状态改为fulfilled(完成)rejected(失败)executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用 resolve 函数来将 promise 状态改成 fulfilled,要么调用 reject 函数将 promise 的状态改为 rejected。如果在 executor 函数中抛出一个错误,那么该 promise 状态为 rejectedexecutor 函数的返回值被忽略。

常规使用方法

resolve

1
2
3
4
5
6
7
8
var pmise = new Promise(function(resolve, reject) {
	setTimeout(() => {
		resolve("delay completed");
	}, 500);
});
pmise.then(function(msg) {
	alert(msg);
});

在500ms之后会执行alert(“deley complted”)。


reject

1
2
3
4
5
6
7
8
9
var pmise = new Promise(function(resolve, reject) {
	setTimeout(() => {
		reject("sorry, error occurred!");
	}, 1000);
});

pmise.catch(function(error) {
	alert(error);
});

catch catch 可以指定 reject 的回调,它还有另外一个作用:在执行 resolve 的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。


finally 方法返回一个 Promise,在 promise 执行结束时,无论结果是 fulfilled 或者是 rejected,在执行 then()catch() 后,都会执行 finally 指定的回调函数。这为指定执行完 promise 后,无论结果是 fulfilled 还是 rejected 都需要执行的代码提供了一种方式,避免同样的语句需要在 then()catch() 中各写一次的情况。

1
2
3
4
5
6
7
8
9
10
var pmise = new Promise(function(resolve, reject) {
	setTimeout(() => {
		reject("sorry, error occurred!");
	}, 1000);
});
pmise.then(xxx)
     .catch(xxx)
     .finally(() => {
         //取消进度条等
     })

描述

Promise 对象是一个代理对象(代理一个值),被代理的值在 Promise 对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的 promise 对象。

一个Promise有几个状态:

  • pending:初始状态,既不是成功也不是失败。
  • fulfilled:意味着操作成功。
  • rejected:意味着操作失败。

pending 状态的 Promise 对象可能会变为 fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilledonrejected,它们都是 Function 类型。当 Promise 状态为 fulfilled 时,调用 thenonfulfilled 方法,当 Promise 状态为 rejected 时,调用 thenonrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。

创建Promise

Promise 对象是由关键字 new 及其构造函数来创建的。该构造函数会把一个叫做 “处理器函数”(executor function)的函数作为它的参数。这个“处理器函数”接受两个函数—— resolvereject ——作为其参数。当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用 reject 函数。

1
2
3
4
5
6
7
let pmise = new Promise((resolve, reject) => {
	// ?做一些异步操作,最终会调用下面两者之一:
	//
	//   resolve(someValue); // fulfilled
	// ?或
	//   reject("failure reason"); // rejected
})

结合其他函数使用:

1
2
3
4
5
6
7
8
9
function simplePromise() {
	return new Promise((resolve, reject) => {
		cost xhr = new XMLHttpRequest();
		xhr.open("xxx");
		xhr.onload = () => resolve(xhr.responseText);
		xhr.onerror = () => reject(xhr.statusText);
		xhr.send();
	})
}

链式调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
clickBtn() {
	this.asyncA().then(obj => {
		alert(obj);
		return this.asyncB();
	}).then(obj => {
		alert(obj);
	}).catch(reason => {
		alert(reason);
	})
},
asyncA() {
	return new Promise((res, rej) => {
		setTimeout(() => {
			res("asyncA completed");
		}, 1000);
	});
},
asyncB() {
	return new Promise((res, rej) => {
		setTimeout(() => {
			res("asyncB completed");
		}, 1000);
	});
}

Promise.all(iterable)

这个方法返回一个新的 promise 对象,该 promise 对象在 iterable 参数对象里所有的 promise 对象都成功的时候才会触发成功,一旦有任何一个 iterable 里面的 promise 对象失败则立即触发该 promise 对象的失败。这个新的 promise 对象在触发成功状态以后,会把一个包含 iterable 里所有 promise 返回值的数组作为成功回调的返回值,顺序跟 iterable 的顺序保持一致;如果这个新的 promise 对象触发了失败状态,它会把 iterable 里第一个触发失败的 promise 对象的错误信息作为它的失败错误信息。Promise.all 方法常被用于处理多个 promise 对象的状态集合。

此实例在 iterable 参数内所有的 promise 都“ 完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。

1
2
3
4
5
6
7
8
9
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(values => {
  console.log(values);
});

输出:

Array [3, 42, “foo”]

Promise.race(iterable)

iterable 参数里的任意一个子 promise 被成功或失败后,父 promise 马上也会用子 promise 的成功返回值或失败详情作为参数调用父 promise 绑定的相应句柄,并返回该 promise 对象。

可以理解为一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。

1
2
3
4
5
6
7
8
9
10
11
12
var promise1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 500, 'one');
});

var promise2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then(function(value) {
  console.log(value);
  // Both resolve, but promise2 is faster
});

上面只会输出:

two

Promise.resolve(value)

返回一个以给定值解析后的 Promise 对象。但如果这个值是个 thenable(即带有then方法),返回的 promise 会“跟随”这个 thenable 的对象,采用它的最终状态(指resolved/rejected/pending/settled);如果传入的 value 本身就是 promise 对象,则该对象作为 Promise.resolve 方法的返回值返回;否则以该值为成功状态返回 promise 对象。

1
2
3
4
5
var promise1 = Promise.resolve(123);

promise1.then(value => {
  console.log(value);
});
1
2
3
4
5
Promise.resolve("Success").then(value => {
  console.log(value); // "Success"
}, reason => {
  // 不会被调用
});
1
2
3
4
var p = Promise.resolve([1,2,3]);
p.then(v => {
  console.log(v[0]); // 1
});

Resolve另一个promise对象

1
2
3
4
5
6
7
8
9
10
11
12
var original = Promise.resolve('我在第二行');
var cast = Promise.resolve(original);
cast.then(function(value) {
  console.log('value: ' + value);
});
console.log('original === cast ? ' + (original === cast));

/*
*  打印顺序如下,这里有一个同步异步先后执行的区别
*  original === cast ? true
*  value: 我在第二行
*/

Promise.reject(reason)

该方法返回一个带有拒绝原因 reason 参数的 Promise 对象。

1
2
3
4
5
Promise.reject(new Error("fail")).then(result => {
  // 未被调用
}, error => {
  console.log(error); // stacktrace
});

详细说明参见Promise