Promise
对象代表着一个还未完成,但预期将来会完成的操作,该新特性属于 ECMAScript 2015(ES6)规范。
使用 Promise
对象,可以十分方便的摆脱层层嵌套的异步操作回调函数,而以同步操作的流程书写代码。Promise
对象主要具有以下两个特点:
Promise
对象的状态只受构造函数内的同步或者一步操作影响,其他外部操作无法改变Promise
对象的状态。Promise
对象的状态改变,只会从pending
变为resolved
或者从pending
变为rejected
,状态改变后不再会发生改变。
浏览器兼容性
Chrome | Edge | Firefox | IE | Opera | Safari |
---|---|---|---|---|---|
32.0 | Yes | 29.0 | 未实现 | 19 | 7.1 |
Promise Constructor
Promise
对象构造器接受一个带有 resolve
和 reject
两个参数的函数,resolve
用于处理执行成功的场景,reject
用于处理执行失败的场景,我们可以根据执行结果决定调用哪个函数处理。
new Promise(function(resolve, reject) { … });
Promise对象有以下几种状态:
- pending: 初始状态;
- resolved: 成功的操作,又称fulfilled;
- rejected: 失败的操作。
示例如下:
var promiseCount = 0; |
输出:
1) 开始(同步代码开始) |
Promise 对象和其原型对象定义几个非常有用的方法:
Promise.prototype.then
then()
方法接收两个函数作为参数,并分别作为 success 和 failure 状态的回调函数,then() 方法返回一个 Promise 对象。
语法
p.then(function(succData){}, function(errData){})
p.then(function(){})
then() 的第二个参数通常省略,因为无法捕获当前then() 函数的异常,而用统一的 catch() 函数进行异常处理,下节详述
then() 使用
then() 方法返回 Promise 对象,因此可以链式调用,而前一个 then() 函数的返回值将会被作为参数传递给下一个 then() 函数:
var p = new Promise(function(resolve, reject) { |
链式调用:
then() 方法返回 Promise 对象,因此可以链式调用,而前一个 then() 函数的返回值将会被作为参数传递给下一个 then() 函数:
var p = new Promise(function(resolve, reject) { |
Promise.prototype.catch
catch()
函数处理 Promise 失败的情形,即在 Promise 中调用了 reject(data) 的情形, 也可以捕获 then() 函数中抛出的错误。
语法
p.catch(function(errData){})
catch使用
var p = new Promise(function(resolve, reject) { |
捕获 Promise 的错误
catch
也能捕获 promise语句中的错误,这种情况类似于在 promise 中调用 reject。
var p = new Promise(function(resolve, reject) { |
捕获 then 函数的错误
var p = new Promise(function(resolve, reject) { |
catch 也支持链式调用
Promise 的错误总是向后抛给 catch 处理的,而 catch 的返回值也是 Promise 因此后一个 catch() 可以处理前一个 catch() 中抛出的错误
建议统一使用 catch 处理异常
尽管通过 then() 方法传递第二个参数可以处理异常,但是无法处理此个 then() 内的异常:
var p = new Promise(function(resolve, reject) { |
Promise.all
Promise.all
方法是 Promise 的一个静态方法,将多个 promise 实例(p1, p2, p3)包装成一个新的 promise 实例(p),此时会有两种执行结果:
- p 会等所有 promise( p1, p2, p3 )都被 resolve 后 resolve,此时将这些 promise ( p1, p2, p3 )的返回值组成一个数组([p1,p2,p3]),传递给 p 的回调函数;
- 如果 p1, p2, p3 中有一个被 reject 则该 reject ,并将该 reject的返回值传递给 p 的回调函数 。
语法:
Promise.all(iterable)
iterable
是一个可迭代对象,比如 Array,iterable 元素可以不是 promise 如果不是 promise 则会使用 Promise.resolve
转换为 Promise。
从多个数据源获取数据
下面是使用 ajax 从多个不同的接口获取数据的示例,如果所有的数据都获取成功,就可以渲染页面,否则报错。
p = Promise.race([ |
Promise.race
Promise.race
方法是 Promise 的一个静态方法,将多个 promise 实例包装成一个新的 promise 实例,和 Promise.all
不同的是,这多个 promise 实例中的任意一个 promise 被解决或拒绝后,立刻以该 promise 的状态和传递的值返回给其回调函数,方法返回一个 Promise。
语法
Promise.race(iterable) //iterable:一个可迭代对象,比如Array。
处理 ajax 异常状态
下面是使用 ajax 获取数据的示例,第二个 promise 在5s后状态会变为 reject ,如果 fetch 在5s 内获取导数据将会正常执行,否则会触发超时错误。
p = Promise.race([ |
Promise.resolve
Promise.resolve
方法将给定的参数转换为一个 Promise 对象,
语法
Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(thenable);
参数是 promise 对象
参数是 promise 对象,则不做操作直接返回这个 promise 对象。
Promise.resolve(Promise.resolve('Hello, world')).then(data => console.log(data)); |
参数是 thenable 对象
如果参数是一个包含 then
方法的对象,resolve
方法会将这个对象转为 Promise 对象,然后执行这个对象的 then
方法。
Promise.resolve({ |
参数不是 thenable 和 promise 对象
如果参数是一个数值,或者是一个非 thenable
或非 promise
的对象,Promise.resolve
方法返回一个状态为 Resolved
的 promise 对象,并把这个参数作为返回值传递给 then
回调函数(如果存在 then 的回调)。
Promise.resolve('Hello, world').then(data => console.log(data)); //Hello, world |
Promise.reject
Promise.reject
方法将给定的参数转换为一个 Promise 对象,
语法
Promise.reject(value);
Promise.reject(promise);
Promise.reject(thenable);
具体的使用情况与 Promise.resolve
类似。