Promise基本概念
关Promise 的使用,在《JavaScript Promise迷你书(中文版)》这本书里面讲解的非常的详细,这边就不在重复,下面只列出来一些比较重要的点和一些比较忽略的地方。
以为promise的知识在迷你书里面看过就记住了,过了一段时间之后发现好多又忘了,这里结合阮老师的ES6-Promise对象重新将Promise的重点给总结一下,放到这篇文档里面,以后方便查阅。
promise定义及特点
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。Promise
也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
promise基本实例
创建promise对象的流程如下所示。
new Promise(fn)返回一个promise对象在
fn中指定异步等处理处理结果正常的话,调用
resolve(处理结果值)处理结果错误的话,调用
reject(Error对象)
function getURL(URL) {
return new Promise(function (resolve, reject) {
var req = new XMLHttpRequest();
req.open('GET', URL, true);
req.onload = function () {
if (req.status === 200) {
resolve(req.responseText);
} else {
reject(new Error(req.statusText));
}
};
req.onerror = function () {
reject(new Error(req.statusText));
};
req.send();
});
}
// 运行示例
var URL = "http://httpbin.org/get";
getURL(URL).then(function onFulfilled(value){
console.log(value);
}).catch(function onRejected(error){
console.error(error);
});promise对象的处理过程只有两种情况, resolve和reject

有一种情况:p1和p2都是 Promise 的实例,但是p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。
const p1 = new Promise(function (resolve, reject) {
// ...
});
const p2 = new Promise(function (resolve, reject) {
// ...
resolve(p1);
})对于这种情况,promise的解决方案是:这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。阮老师Promise对象里面有关于这种情况的一个例子。
promise结束状态
调用resolve或reject并不会终结 Promise 的参数函数的执行。
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1promise方法链
var promise = Promise.resolve();
promise
.then(taskA)
.then(taskB)
.catch(onRejected)
.then(finalTask);上面代码中的promise chain的执行流程,如果用一张图来描述一下的话,像下面的图那样。

如果Task A 处理中发生异常的话,会按照TaskA → onRejected → FinalTask 这个流程来进行处理。

finally()
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
Promise.all()
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);上面代码中,Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
注意事项:
1、如果作为参数的 Promise 实例,自己定义了
catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。2、如果其中的某一个promise实例
p1或p2或p3没有自己的catch方法,就会调用Promise.all()的catch方法。
Promise.race()
Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);上面代码中,只p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
有时候设定了一个时间限制,如果规定时间内
p1 p2 p3都没有改变状态,那p的状态变成reject
Promise.resolve()
Promise.resolve方法可以将现有对象转为 Promise 对象。
Promise.resolve方法的参数分成四种情况。
(1)参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable对象
thenable对象指的是具有then方法的对象,Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
(3)参数不是具有then方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。
4)不带有任何参数
Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
promise的返回
专栏: 每次调用then都会返回一个新创建的promise对象 {#then-return-new-promise}
从代码上乍一看,aPromise.then(...).catch(...)像是针对最初的aPromise对象进行了一连串的方法链调用。
然而实际上不管是then还是catch方法调用,都返回了一个新的promise对象
// 1: 对同一个promise对象同时调用 `then` 方法
var aPromise = new Promise(function (resolve) {
resolve(100);
});
aPromise.then(function (value) {
return value * 2;
});
aPromise.then(function (value) {
return value * 2;
});
aPromise.then(function (value) {
console.log("1: " + value); // => 100
})
// vs
// 2: 对 `then` 进行 promise chain 方式进行调用
var bPromise = new Promise(function (resolve) {
resolve(100);
});
bPromise.then(function (value) {
return value * 2;
}).then(function (value) {
return value * 2;
}).then(function (value) {
console.log("2: " + value); // => 100 * 2 * 2
});Promise.try()
对于不知道或者不想区分的通过或者异步操作,但是想用promise处理,以前常用的方法有两种,一种是使用async函数,
const f = () => console.log('now');
(async () => f())(); //同步
// (async () => f())().then(...) //异步
console.log('next');
// now
// next第二种写法是使用new Promise()。
const f = () => console.log('now');
(
() => new Promise(
resolve => resolve(f())
)
)();
console.log('next');
// now
// next所以提出一个提案,Promise.try()
const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next参考
Last updated