超级面板
文章目录
最新文章
最近更新
文章分类
标签列表
文章归档

Promise特性总结

Promise 对象代表着一个还未完成,但预期将来会完成的操作,该新特性属于 ECMAScript 2015(ES6)规范。
使用 Promise 对象,可以十分方便的摆脱层层嵌套的异步操作回调函数,而以同步操作的流程书写代码。
Promise 对象主要具有以下两个特点:

  1. Promise 对象的状态只受构造函数内的同步或者一步操作影响,其他外部操作无法改变 Promise 对象的状态。
  2. Promise 对象的状态改变,只会从 pending 变为 resolved 或者从 pending 变为rejected,状态改变后不再会发生改变。

浏览器兼容性

Chrome Edge Firefox IE Opera Safari
32.0 Yes 29.0 未实现 19 7.1

Promise Constructor

Promise 对象构造器接受一个带有 resolvereject 两个参数的函数,resolve 用于处理执行成功的场景,reject 用于处理执行失败的场景,我们可以根据执行结果决定调用哪个函数处理。

new Promise(function(resolve, reject) { … });

Promise对象有以下几种状态:

  • pending: 初始状态;
  • resolved: 成功的操作,又称fulfilled;
  • rejected: 失败的操作。

示例如下:

var promiseCount = 0;
function testPromise() {
var thisPromiseCount = ++promiseCount;

console.log(thisPromiseCount + ') 开始(同步代码开始)');

// 我们创建一个新的promise: 然后用'result'字符串完成这个promise (3秒后)
var p1 = new Promise(function (resolve, reject) {
// 完成函数带着完成(resolve)或拒绝(reject)promise的能力被执行
console.log(thisPromiseCount + ') Promise开始(异步代码开始)');
console.log('//等待若干秒');

// 这只是个创建异步完成的示例
window.setTimeout(function () {
// 我们满足(fullfil)了这个promise!
resolve(thisPromiseCount)
}, Math.random() * 2000 + 1000);
});

// 定义当promise被满足时应做什么
p1.then(function (val) {
// 输出一段信息和一个值
console.log(val + ') Promise被满足了(异步代码结束)');
});

console.log(thisPromiseCount + ') 建立了Promise(同步代码结束)');
}
testPromise();
testPromise();
testPromise();

输出:

1) 开始(同步代码开始)
1) Promise开始(异步代码开始)
//等待若干秒
1) 建立了Promise(同步代码结束)
2) 开始(同步代码开始)
2) Promise开始(异步代码开始)
//等待若干秒
2) 建立了Promise(同步代码结束)
3) 开始(同步代码开始)
3) Promise开始(异步代码开始)
//等待若干秒
3) 建立了Promise(同步代码结束)

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) {
resolve("SUCCESS");
//or
//reject("FAILURE");
});

p.then(function(succData){
console.log(succData);//success
}, function(errData){
console.log(errData);//failure
});

链式调用:

then() 方法返回 Promise 对象,因此可以链式调用,而前一个 then() 函数的返回值将会被作为参数传递给下一个 then() 函数:

var p = new Promise(function(resolve, reject) {
resolve(1);
});

p.then(function(val) {
console.log(val); // 1
return val + 1;
}).then(function(val) {
console.log(val); // 2
}).then(function(val) {
console.log(val); // 3
});

Promise.prototype.catch

catch() 函数处理 Promise 失败的情形,即在 Promise 中调用了 reject(data) 的情形, 也可以捕获 then() 函数中抛出的错误。

语法

p.catch(function(errData){})

catch使用

var p = new Promise(function(resolve, reject) {
//resolve("SUCCESS");
//or
reject("FAILURE");
});

p.then(function(succData){
console.log(succData);//success
}).catch(function(errData){
console.log(errData);//failure
});
//实际上等同于
p.then(function(succData){
console.log(succData);//success
}.then(null, function(errData){
console.log(errData);//failure
});

捕获 Promise 的错误

catch 也能捕获 promise语句中的错误,这种情况类似于在 promise 中调用 reject。

var p = new Promise(function(resolve, reject) {
throw("FAILURE");
});

p.then(function(succData){
throw new Error('FAILURE'); //不执行
}).catch(function(errData){
console.log(errData);//FAILURE
});

捕获 then 函数的错误

var p = new Promise(function(resolve, reject) {
resolve("SUCCESS");
});

p.then(function(succData){
throw new Error('FAILURE');
}).catch(function(errData){
console.log(errData);//FAILURE
});

catch 也支持链式调用

Promise 的错误总是向后抛给 catch 处理的,而 catch 的返回值也是 Promise 因此后一个 catch() 可以处理前一个 catch() 中抛出的错误

建议统一使用 catch 处理异常

尽管通过 then() 方法传递第二个参数可以处理异常,但是无法处理此个 then() 内的异常:

var p = new Promise(function(resolve, reject) {
reject(FAILURE1);
});

p.catch(function(errData){
console.log(errData);//FAILURE1
throw new Error('FAILURE2');
}).catch(function(errData){
console.log(errData);//FAILURE2
});

Promise.all

Promise.all 方法是 Promise 的一个静态方法,将多个 promise 实例(p1, p2, p3)包装成一个新的 promise 实例(p),此时会有两种执行结果:

  1. p 会等所有 promise( p1, p2, p3 )都被 resolve 后 resolve,此时将这些 promise ( p1, p2, p3 )的返回值组成一个数组([p1,p2,p3]),传递给 p 的回调函数;
  2. 如果 p1, p2, p3 中有一个被 reject 则该 reject ,并将该 reject的返回值传递给 p 的回调函数 。

语法:

Promise.all(iterable)

iterable 是一个可迭代对象,比如 Array,iterable 元素可以不是 promise 如果不是 promise 则会使用 Promise.resolve 转换为 Promise。

从多个数据源获取数据

下面是使用 ajax 从多个不同的接口获取数据的示例,如果所有的数据都获取成功,就可以渲染页面,否则报错。

p = Promise.race([
fetch('/resource/data1.json'),
fetch('/resource/data2.json'),
fetch('/resource/data3.json'),
]).then(([d1, d2, d3]) => {
//render page
}).catch(err => {
//err handler
});

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([
fetch('/resource/data.json'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
]).then(response => {
//use data do sth
}).catch(error => {
//err handler
})

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({
then(resolve, reject) {
resolve('Hello, world');
}
}).then(data => console.log(data));//Hello, world

参数不是 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 类似。

参考:

  1. Promise
  2. Promise对象