Promise是ES 6中新增的对象,Promise本质上是一种对异步处理的规范。Promise非常适合处理JS深度嵌套回调的问题,通过Promise处理回调可以使代码更简洁也更易读。主流浏览器(IE除外)的最新版本,已经提供了对ECMAScript 6的支持。Node.js自V 4.0 起,开始原生支持ECMAScript 6。所以,现在使用Promise已不需要额外引用包或模块,本文将分别介绍在浏览器中和在Node.js中使用Promise的链式调用。
1. Promise简单回顾
本站曾整理过几篇关于Promise介绍的文章。再简单回顾一下:创建一个Promise对象使用构造函数new Promise(),该函数接受一个函数参数,该函数包含两个参数:resolve、reject,这两个参数是两个回调函数,分别用于执行成功和执行失败时回调。
var promise = new Promise(function(resolve, reject) {
if (true){
//操作成功时调用
resolve(value);
} else {
//操作失败时调用
reject(error);
}
});
Promise包含两个实例方法:then、catch。
then方法可以处理正常和异常两种情况,它有两个参数(函数参数)。第一个函数参数用于处理操作成功的情况,第二个函数参数用于处理操作失败的情况。catch方法只能异常情况,它一个参数(函数参数),该参数用于处理操作失败的情况。
因此,对于操作成功和操作失败的处理,可以使用以下两种形式。
只使用then方法,处理操作成功和操作失败的情况:
promise.then(function(result) {
// 操作成功
}, function(err) {
// 操作失败
});
使用then方法处理操作成功的情况,使用catch方法处理操作失败的情况:
promise.then(function(result) {
// 操作成功
}).catch(function(err) {
// 操作失败
});
Promise实现链式调用
then方法也可以接受另一个Promise实例的传入,或thenable对象(包含then的对象或方法)。因此,在前一步的then方法中,只要在操作成功中返回一个Promise实例或thenable对象,就可以实现类似then().then().then().catch()形式的链式调用。这样只需要在每一个then()处理正常情况,只要在最后的catch()方法中处理异常情况即可。
示例如下:
promise.then(function(result){
//上一步操作成功
console.log(result);
//返回另一个thenable对象
return new Promise(……);
}).then(function(result){
//上一步操作成功
console.log(result);
//返回另一个thenable对象
return new Promise(……);
}).then(function(result){
//上一步操作成功
console.log(result);
//返回另一个thenable对象
return new Promise(……);
}).catch(function(error){
//处理异常
console.log(error);
});
2. 在浏览器中使用Promise的链式调用
现在有getURL方法,该使用XMLHttpRequest进行HTTP请求,该方法的返回值是一个Promise对象实例。下面使用这个方法以链式调用的形式分别请求两个网址:
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();
});
}
getURL('https://api.github.com').then(function(result){
//第一次请求的结果
console.log(result);
return getURL('https://nodejs.org/api/index.json');
}).then(function(result){
//第二次请求的结果
console.log(result);
}).catch(function(error){
//请求失败
console.log(error);
});
3. 在Node.js中使用Promise的链式调用
现有readFile方法,该方法使用fs模块读取文件,其返回值是一个Promise对象实例。下面使用这个方法以链式调用的形式,分别读取a.txt、b.txt两个文件:
var fs = require('fs');
function readFile(file){
return new Promise(function(resolve, reject){
fs.readFile(file, function(err, result){
if(err){
reject(err);
} else {
resolve(result);
}
});
});
}
readFile('./a.txt').then(function(result){
//显示第一个文件的读取结果
console.log(result.toString());
//返回另一个Promise对象实例
return readFile('./b.txt');
}).then(function(result){
//显示第二个文件的读取结果
console.log(result.toString());
}).catch(function(error){
//文件读取失败
console.log(error);
});
