Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最先提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了 Promise 对象。javascript
所谓 Promise,简单说就是一个容器,里面保存着某个将来才会结束的事件(一般是一个异步操做)的结果。从语法上说,Promise 是一个对象,从它能够获取异步操做的消息。Promise 提供统一的 API,各类异步操做均可以用一样的方法进行处理。html
Promise 对象有如下两个特色:java
使用 Promise 对象的好处在于:编程
Promise 缺点:数组
ES6 规定,Promise 对象是一个构造函数,用来生成 Promise 实例。promise
const promise = new Promise((resolve, reject) => { setTimeout(() => { const num = Math.random(); if (num > 0.5) { resolve(num); } else { reject(num); } }, 500); }); promise.then( res => { console.log("成功:" + res); }, err => { console.log("失败:" + err); } );
Promise 构造函数接受一个函数做为参数,该函数的两个参数分别是 resolve 和 reject。它们是两个函数,由 JavaScript 引擎提供,不用本身部署。dom
const promise = new Promise((resolve, reject) => { setTimeout(() => { const num = Math.random(); if (num > 0.5) { resolve(num); } else { reject(num); } }, 500); }); promise .then(res => { console.log("成功:" + res); }) .catch(err => { console.log("失败:" + err); }); promise .then(res => { console.log("成功:" + res); throw new Error("test"); }) .catch(err => { // num > 0.5时打印 "失败:Error: test" console.log("失败:" + err); });
Promise 新建后当即执行,then 方法指定的回调函数,将在当前脚本全部同步任务执行完才会执行,catch 同理。异步
调用 resolve 或 reject 并不会终结 Promise 的参数函数的执行。异步编程
const promise = new Promise((resolve, reject) => { console.log("我是第一个执行的"); resolve(); }); promise.then(res => { console.log("我是第三个执行的"); }); console.log("我是第二个执行的");
reject 函数的参数一般是 Error 对象的实例,表示抛出的错误;resolve 函数的参数除了正常的值之外,还多是另外一个 Promise 实例。函数
若是一个 Promise(P2) 的 resolve 参数是另外一个 Promise(P1),此时 P1 的状态就会传给 P2,P1 的状态决定了 P2 的状态,P1 的状态改变,P2 的回调函数才会执行。
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 方法返回的是 p1。因为 p2 返回的是另外一个 Promise,致使 p2 本身的状态无效了,由 p1 的状态决定 p2 的状态。因此,后面的 then 语句都变成针对后者(p1)。又过了 2 秒,p1 变为 rejected,致使触发 catch 方法指定的回调函数。
then 方法能够返回一个新的 Promise 实例(注意,不是原来那个 Promise 实例)。所以能够采用链式写法,即 then 方法后面再调用另外一个 then 方法。
const promise = new Promise((resolve, reject) => { resolve("promise"); }) .then(res => { console.log(res); // promise return "promise1"; }) .then(res => { console.log(res); // promise1 return "promise2"; }) .then(res => { console.log(res); // promise2 });
注意:只要一个 Promise 中抛出错误,将执行 catch 方法,then 链终止。
const promise = new Promise((resolve, reject) => { resolve("promise"); }) .then(res => { console.log(res); // promise throw new Error("停止"); return "promise1"; }) .then(res => { console.log(res); return "promise2"; }) .then(res => { console.log(res); }) .catch(err => { console.log(err); // Error: 停止 });
主动终止 then 链,经过 catch 方法来停止 promise chain
const promise = new Promise((resolve, reject) => { resolve("promise"); }) .then(res => { console.log(res); // promise return Promise.reject({ notRealPromiseException: true }); }) .then(res => { console.log(res); return "promise2"; }) .then(res => { console.log(res); }) .catch(err => { if (err.notRealPromiseException) { return true; } console.log(err); });
finally 方法用于指定无论 Promise 对象最后状态如何,都会执行的操做。该方法是 ES2018 引入标准的。
finally 本质上是 then 方法的特例,不接受任何参数,不依赖于 Promise 的执行结果
promise.finally(() => { // 语句 }); // 等同于 promise.then( result => { // 语句 return result; }, error => { // 语句 throw error; } );
Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const promise = Promise.all([promise1, promise2, promise3])
Promise.all 方法接受一个数组做为参数,promise、pro 米色、promise3 都是 Promise 实例,若是不是,就会先调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。(Promise.all 方法的参数能够不是数组,但必须具备 Iterator 接口,且返回的每一个成员都是 Promise 实例。了解 Iterator 接口)
promise 的状态由 promise一、promise二、promise3 决定,分红两种状况。
const p1 = new Promise((resolve, reject) => { resolve("hello"); }) .then(result => result) .catch(e => e); const p2 = new Promise((resolve, reject) => { throw new Error("报错了"); }) .then(result => result) .catch(e => e); Promise.all([p1, p2]) .then(result => console.log(result)) .catch(e => console.log(e)); // ["hello", Error: 报错了]
上面代码中,p1 会 resolved,p2 首先会 rejected,可是 p2 有本身的 catch 方法,该方法返回的是一个新的 Promise 实例,p2 指向的其实是这个实例。该实例执行完 catch 方法后,也会变成 resolved,致使 Promise.all()方法参数里面的两个实例都会 resolved,所以会调用 then 方法指定的回调函数,而不会调用 catch 方法指定的回调函数。
若是 p2 没有本身的 catch 方法,就会调用 Promise.all()的 catch 方法。
Promise.race 方法一样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3])
只要 p一、p二、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。
Promise.race 方法的参数与 Promise.all 方法同样,若是不是 Promise 实例,就会先调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。
将现有对象转化为 Promise 对象。
const promise = Promise.resolve('Hello world')
let thenObj = { then(resolve, reject) { resolve("Hello"); } }; const promise = Promise.resolve(thenObj); promise.then(res => { console.log(res); // Hello });
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为 rejected。