Promise对象已在ECMAScript 2015中被写入标准,且已被最新版本的浏览器和Node.js/IO.js所支持。bluebird是一个第三方Promise规范实现库,它不仅完全兼容原生Promise对象,且比原生对象功能更强大。
相关介绍
1 bluebird与Promise
JavaScript中有很多第三方的Promise库,在ECMAScript 2015(ES 6)中也实现了一个Promise对象,可以在最新版本的浏览器和Node.js/IO.js中使用。
bluebird同样是一个第三方Promise类库,相比其它第三方类库或标准对象来说,其有以下优点:功能更齐全而不臃肿、浏览器兼容性更好。
2 Promise对象
Promise对象已在ECMAScript 2015中做为JavaScript的标准内置对象提供,这个对象根据Promise A+规范实现,相对比较简单。除从Object对象中继承对象属性/方法外,它还有以下Promise自身的属性/方法。简单介绍如下:
Promise中的类方法
JavaScript中的类(对象)方法可以认为是静态方法(即:不需要实例化就可以使用的方法)。Promise中有以下类方法:
Promise.all(promiseArray)- 将多个Promise实例包装成一个新实例,多个实例会同时执行成功或失败Promise.race(promiseArray)- 将多个Promise实例包装成一个新实例,实例中的任何一个实例执行成功或失败将返回Promise.resolve(obj)- 将对象包装成resolve状态的Promise实例Promise.reject(obj) - 将对象包装成 reject状态的Promise实例
Promise中的实例方法
实例方法,是指创建Promise实例后才能使用的方法,即:被添加到原型链Promise.prototype上的方法。Promise中有以下实例方法:
promise.then(onFulfilled, onRejected)- 执行成功(或/与)失败的处理promise.catch(onRejected)- 执行失败的处理
Promise A+规范规定:每个Promise实例中返回的都应该是一个Promise实例或thenable对象。基于这个特性,能够实现类似于同步的链式调用。
3 bluebird模块
bluebird是一个第三方的Promise实现,我们可通过npm命令来安装:
npm install bluebird
模块安装后,可以就可以通过require获取对模块的引用:
var Promise = require('bluebird');
bluebird模块除Promise对象中的方法外,还有很多扩展方法。如,可以通过.spread()展开结构集、可以通过Promise.promisify()方法将一个Node回调函数包装成一个Promise实例。
bluebird中主要API如下:
- 核心(Core)
- 1.1
new Promise- 创建实例 - 1.2
.then- 实例的then()方法 - 1.3
.spread- 展开实例返回的结果数组 - 1.4
.catch- 实例异常处理方法 - 1.5
.error- 实例操作异常处理 - 1.6
.finally- 实例最终调用方法 - 1.7
Promise.join- 关联多个不相关的实例 - 1.8
Promise.try- 包装为Promise实例 - 1.9
Promise.method- 将函数包装为返回Promise实例的函数 - 1.10
Promise.resolve- 包装值为Promiseresolved实例 - 1.11
Promise.reject- 包装值为Promisereject实例
- 1.1
- 同步检查(Synchronous inspection)
- 集合操作(Collections)
- 3.1
Promise.all- 执行多个Promise实例 - 3.2
Promise.props- 对象属性包装成Promise实例 - 3.3
Promise.any- 执行成1个即返回 - 3.4
Promise.some- 成功指定次数后返回 - 3.5
Promise.map- Map操作 - 3.6
Promise.reduce- Reduce操作 - 3.7
Promise.filter- filter过滤 - 3.8
Promise.each- 依次执行 - 3.9
Promise.mapSeries- 顺序执行的Map操作 - 3.10
Promise.race- 非Promise对象包成Promise对象 - 3.11
.all- 实例all方法 - 3.12
.props- 实例props方法 - 3.13
.any- 实例any方法 - 3.14
.some- 实例some方法 - 3.15
.map- 实例map方法 - 3.16
.filter- 实例filter方法 - 3.17
.each- 实例each方法 - 3.18
.mapSeries- 实例mapSeries方法
- 3.1
- 资源管理(Resource management)
Promise包装器(Promisification)- 定时器(Timers)
- 工具方法(Utility)
1. 核心方法(Core)
核心方法包括Promise实例和Promise对象中的核心静态方法。
1.1 new Promise - 创建实例
new Promise(function(function resolve, function reject) resolver) -> Promise
该方法是一个构造函数,用于创建一个新的Promise实例。该方法与Promise A+规范实现一致,传入的函数参数中有两个参数:resolve和reject,这两个参数被封装到所创建的Promise实例中,分别用于执行成功和执行失败时的调用。
如,我们可以将XMLHttpRequest对象AJAX请求封装成一个Promise对象:
function ajaxGetAsync(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.addEventListener("error", reject);
xhr.addEventListener("load", resolve);
xhr.open("GET", url);
xhr.send(null);
});
}
然后我就可以像下面这样进行AJAX请求:
ajaxGetAsync('http://niefengjun.cn')
.then(function(result){
// 请求成功的处理
})
.catch(function(err){
// 请求失败的处理
})
在使用Promise进行处理时,要确保每一步都要返回一个Promise实例,并进行链式处理。如果不能立即开始一个Promise链式处理,可以使用new Promise来构造一个实例:
function getConnection(urlString) {
return new Promise(function(resolve) {
//不使用 new Promise时,这里会显式的抛出一个异常
var params = parse(urlString);
resolve(getAdapter(params).getConnection());
});
}
1.2 .then - 实例的then()方法
.then( [function(any value) fulfilledHandler], [function(any error) rejectedHandler] ) -> Promise
Promise A+ 规范中的.then()方法,该方法可以同时传入用于操作成功后调用的fulfilledHandler回调函数和用于操作失败后调用的rejectedHandler回调函数,也可以只传入其中的一个。
参考:Promise 对象的实例方法。
1.3 .spread - 展开实例返回的结果数组
.spread( [function(any values...) fulfilledHandler] ) -> Promise
类似调用.then方法,但执行成功后的值(fulfillment值)必须是一个数组,它会将参数扁平化并分别调用fulfilledHandler处理函数。
Promise.delay(500).then(function() {
return [fs.readFileAsync("file1.txt"),
fs.readFileAsync("file2.txt")] ;
}).spread(function(file1text, file2text) {
if (file1text !== file2text) {
console.log("files are equal");
} else {
console.log("files are not equal");
}
});
而使用ES 6规范进行处理时,可以像下面这样操作:
Promise.delay(500).then(function() {
return [fs.readFileAsync("file1.txt"),
fs.readFileAsync("file2.txt")] ;
}).all().then(function([file1text, file2text]) {
if (file1text !== file2text) {
console.log("files are equal");
} else {
console.log("files are not equal");
}
});
注意:.spread()方法会隐式的调用.all()方法,而在ES6中要显式的调用。
1.4 .catch - 实例异常处理方法
.catch是Promise链式处理中的用于异常处理的便捷方法。这个方法有两个变体:一个用于捕获所有错误,类似catch(e) {的同步方法;一个是用于捕获指定错误的变体方法。
promise中的异常捕获
function getItems(param) {
return getItemsAsync().then(items => {
if(!items) throw new InvalidItemsError();
return items;
}).catch(e => {
// 从 getItemsAsync 中返回一个 rejects 或 假值时,可以从这里解决和恢复错误
throw e;
// Need to rethrow unless we actually recovered, just like in the synchronous version
}).then(process);
}
捕获所有异常
.catch(function(any error) handler) -> Promise
.caught(function(any error) handler) -> Promise
捕获所有异常是promise中.then(null, handler)的便捷方法,.then链中异常会被传递到.catch中。
为了能和ECMASript早期版本兼容,为.catch添加了一个别名方法.caught
捕获部分异常
.catch( class ErrorClass|function(any error)|Object predicate..., function(any error) handler ) -> Promise
.caught( class ErrorClass|function(any error)|Object predicate..., function(any error) handler ) -> Promise
部分捕获类似Java或C#中的catch分句,可以通过错误构造函数来进行异常的捕获处理。
somePromise.then(function() {
return a.b.c.d();
}).catch(TypeError, function(e) {
//If it is a TypeError, will end up here because
//it is a type error to reference property of undefined
}).catch(ReferenceError, function(e) {
//Will end up here if a was never declared at all
}).catch(function(e) {
//Generic catch-the rest, error wasn't TypeError nor
//ReferenceError
});
也可以在一个.catch分句中捕获多个错误:
somePromise.then(function() {
return a.b.c.d();
}).catch(TypeError, ReferenceError, function(e) {
//Will end up here on programmer error
}).catch(NetworkError, TimeoutError, function(e) {
//Will end up here on expected everyday network errors
}).catch(function(e) {
//Catch any unexpected errors
});
1.5 .error - 实例操作异常处理
.error([function(any error) rejectedHandler]) -> Promise
类似.catch,但它只捕获和处理操作错误。
与.catch处理相比:
// 假定会全局触发一个 OperationalError 异常
function isOperationalError(e) {
if (e == null) return false;
return (e instanceof OperationalError) || (e.isOperational === true);
}
// catch 捕获
.catch(isOperationalError, function(e) {
// ...
})
// 等价于:
.error(function(e) {
// ...
});
如,我们可能希望捕获JSON.parse引发的SyntaxError错误和fs文件操作相关错误,可以像下面这样传递处理错误:
var fs = Promise.promisifyAll(require("fs"));
fs.readFileAsync("myfile.json").then(JSON.parse).then(function (json) {
console.log("Successful json")
}).catch(SyntaxError, function (e) {
console.error("file contains invalid json");
}).error(function (e) {
console.error("unable to read file, because: ", e.message);
});
1.6 .finally - 实例最终调用方法
.finally(function() handler) -> Promise
.lastly(function() handler) -> Promise
这个方法不会考虑Promise实例的执行状态,而始终会调用并返回一个新promise链。
考虑如下一个处理:
function anyway() {
$("#ajax-loader-animation").hide();
}
function ajaxGetAsync(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.addEventListener("error", reject);
xhr.addEventListener("load", resolve);
xhr.open("GET", url);
xhr.send(null);
}).then(anyway, anyway);
}
在上在操作中,我们期望的操作是无论执行结果如果,都要将元素隐藏,这样我们需要在.then链的两种执行状态中分别传入隐藏方法。
这种情况非常适合使用.finally处理:
function ajaxGetAsync(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.addEventListener("error", reject);
xhr.addEventListener("load", resolve);
xhr.open("GET", url);
xhr.send(null);
}).finally(function() {
$("#ajax-loader-animation").hide();
});
}
1.7 Promise.join - 关联多个不相关的实例
Promise.join( Promise<any>|any values..., function handler ) -> Promise
关联多个不相关的Promise实例。.all很适合处理统一处理动态大小的列表,而.join使处理多个离散的Promise实例处理更加容易。
在这个方法,方法的最后一个参数是一个回调函数,其中包含所有的处理成功的结果:
var Promise = require("bluebird");
var join = Promise.join;
join(getPictures(), getComments(), getTweets(),
function(pictures, comments, tweets) {
console.log("in total: " + pictures.length + comments.length + tweets.length);
});
1.8 Promise.try - 包装为Promise实例
Promise.try(function() fn) -> Promise
Promise.attempt(function() fn) -> Promise
通过Promise.try启动一个promise链,并将所有同步异常封装到promise的reject处理中:
function getUserById(id) {
return Promise.try(function() {
if (typeof id !== "number") {
throw new Error("id must be a number");
}
return db.getUserById(id);
});
}
在上面示例中,经过Promise.try封装后,其同步和异步异常都可以通过.catch来捕获。
1.9 Promise.method - 将函数包装为返回Promise实例的函数
Promise.method(function(...arguments) fn) -> function
包装指定的函数fn,包装后函数会返回一个Promise实例。
如,对于如下一个不使用Promise.method包装的方法:
MyClass.prototype.method = function(input) {
if (!this.isValid(input)) {
return Promise.reject(new TypeError("input is not valid"));
}
if (this.cache(input)) {
return Promise.resolve(this.someCachedValue);
}
return db.queryAsync(input).bind(this).then(function(value) {
this.someCachedValue = value;
return value;
});
};
通过Promise.method对包装以方法时:
MyClass.prototype.method = Promise.method(function(input) {
if (!this.isValid(input)) {
throw new TypeError("input is not valid");
}
if (this.cache(input)) {
return this.someCachedValue;
}
return db.queryAsync(input).bind(this).then(function(value) {
this.someCachedValue = value;
return value;
});
});
1.10 Promise.resolve - 包装值为Promiseresolved实例
Promise.resolve(Promise<any>|any value) -> Promise
通过指定值创建Promiseresolved实例。如果值已使用Promise,那会返回它。如果值不是thenable对象,会将其包装成一个会执行成功的Promise实例,该值将会做为fulfillment值返回。
Promise.resolve($.get("http://www.google.com")).then(function() {
// 从处理函数中返回一个thenable,按Promises/A+ 规范自动载换为可信的Promise
return $.post("http://www.yahoo.com");
}).then(function() {
}).catch(function(e) {
//jQuery 不会抛出真的错误,所以使用 catch-all
console.log(e.statusText);
});
1.11 Promise.reject - 包装值为Promisereject实例
Promise.reject(any error) -> Promise
将指定的值包装为一个rejected状态的Promise实例
2. 同步检查(Synchronous inspection)
同步检查相关API,是指用于Promise实例检查的一些方法。
2.1 PromiseInspection接口
interface PromiseInspection {
any reason()
any value()
boolean isPending()
boolean isRejected()
boolean isFulfilled()
boolean isCancelled()
}
这个接口会被Promise实例实现,PromiseInspection结果通过.reflect()方法提供。
2.2 isFulfilled - 检查是否执行成功
.isFulfilled() -> boolean
检查promise是否执行成功
2.3 isRejected - 检查是否执行失败
.isRejected() -> boolean
检查promise是否执行失败
2.4 isPending - 检查是否处理中
.isPending() -> boolean
检查promise是否处理中(非fulfilled、rejected或cancelled)
2.5 isCancelled - 检查是否已取消
.isCancelled() -> boolean
检查promise是否已取消
2.6 value - 执行结果
.value() -> any
返回promise的执行结果,需要通过.isFulfilled()来判断已执行成功
2.7 reason - 执行失败原因
.reason() -> any
返回promise的执行失败的原因,需要通过.isRejected()来判断已执行失败
3. 集合操作(Collections)
3.1 Promise.all - 执行多个Promise实例
Promise.all(Iterable<any>|Promise<Iterable<any>> input) -> Promise
等待多个Promise实例执行完成,
参数是一个Iterable(可迭代)对象(如:promise数组)。在这个方法中,promise数组中所有的promise实例都变为resolve的时候,该方法才会返回,并将所有结果传递到结果数组中。promise数组中任何一个promise为reject的话,则整个Promise.all调用会立即终止,并返回一个状态为reject的新的promise对象。
var files = [];
for (var i = 0; i < 100; ++i) {
files.push(fs.writeFileAsync("file-" + i + ".txt", "", "utf-8"));
}
Promise.all(files).then(function() {
console.log("all the files were created");
});
3.2 Promise.props - 对象属性包装成Promise实例
Promise.props(Object|Map|Promise<Object|Map> input) -> Promise
Promise.props功能与Promise.all功能类型,不同的是访方法用于对象属性或Map实体而不是可迭代值,即把对象或Map实体的函数属性键变为Promise实例。对象属性或Map实体全部执行通过后返回一个promise,这个promise对象的fulfillment值是一个拥有原对象或Map键值的对象或Map。
Promise.props({
pictures: getPictures(),
comments: getComments(),
tweets: getTweets()
}).then(function(result) {
console.log(result.tweets, result.pictures, result.comments);
});
3.3 Promise.any - 执行成1个即返回
Promise.any(Iterable<any>|Promise<Iterable<any>> input) -> Promise
类似Promise.any,但成功数为1。promise执行成功后,实现值不是数组而1个直接值。
3.4 Promise.some - 成功指定次数后返回
Promise.some( Iterable<any>|Promise<Iterable<any>> input, int count ) -> Promise
指定的Iterable数组或Iterablepromise,执行成功指定次数count后即返回,实现值是一个数组
如,ping 4个网址,返回最快的2个:
Promise.some([
ping("ns1.example.com"),
ping("ns2.example.com"),
ping("ns3.example.com"),
ping("ns4.example.com")
], 2).spread(function(first, second) {
console.log(first, second);
});
3.5 Promise.map - Map操作
Promise.map(
Iterable<any>|Promise<Iterable<,
function(any item, int index, int length) mapper,
[Object {concurrency: int=Infinity} options]
) -> Promise
为指定的Iterable数组或Iterablepromise,执行一个处理函数mapper并返回执行后的数组或Iterablepromise。
Promises会等待mapper全部执行完成后返回,如果数组中的promise执行全部分成功则Promises中是执行成功值。如果任何一个promise执行失败,Promises对应的也是拒绝值。
Promise.map可以用于替数组.push+Promise.all方法:
// 对于如下一个操作:
var promises = [];
for (var i = 0; i < fileNames.length; ++i) {
promises.push(fs.readFileAsync(fileNames[i]));
}
Promise.all(promises).then(function() {
console.log("done");
});
// 使用 Promise.map处理如下:
Promise.map(fileNames, function(fileName) {
// Promise.map 等待操作成功后返回
return fs.readFileAsync(fileName);
}).then(function() {
console.log("done");
});
3.6 Promise.reduce - Reduce操作
Promise.reduce( Iterable<any>|Promise<Iterable<, function(any accumulator, any item, int index, int length) reducer, [any initialValue] ) -> Promise
为指定的Iterable数组或Iterablepromise,执行一个处理函数reducer,并返回一个经过Reduce处理后promise。
reducer函数会最终返回一个promise。数组中的所有promise处理成功后,会返回一个成功状态的promise,任何一个执行失败都会返回一个拒绝状态的promise。
如,使用Promise.reduce计算从三个文件中读取值的总和,每个文件中都有一个数字10:
Promise.reduce(["file1.txt", "file2.txt", "file3.txt"], function(total, fileName) {
return fs.readFileAsync(fileName, "utf8").then(function(contents) {
return total + parseInt(contents, 10);
});
}, 0).then(function(total) {
//Total is 30
});
3.7 Promise.filter - filter过滤
Promise.filter(
Iterable<any>|Promise<Iterable<,
function(any item, int index, int length) filterer,
[Object {concurrency: int=Infinity} options]
) -> Promise
为指定的Iterable数组或Iterablepromise,执行一个过滤函数filterer,并返回经过筛选后promises数组。
var Promise = require("bluebird");
var E = require("core-error-predicates");
var fs = Promise.promisifyAll(require("fs"));
fs.readdirAsync(process.cwd()).filter(function(fileName) {
return fs.statAsync(fileName)
.then(function(stat) {
return stat.isDirectory();
})
.catch(E.FileAccessError, function() {
return false;
});
}).each(function(directoryName) {
console.log(directoryName, " is an accessible directory");
});
3.8 Promise.each - 依次执行
Promise.each( Iterable<any>|Promise<Iterable>, function(any item, int index, int length) iterator ) -> Promise
为指定的Iterable数组或Iterablepromise,执行一个函数iterator,该函数参数为(value, index, length),value输入数组中promise的resolved值。
iterator函数会最终返回一个promise。数组中的所有promise处理成功后,会返回一个成功状态的promise,任何一个执行失败都会返回一个拒绝状态的promise。
3.9 Promise.mapSeries - 顺序执行的Map操作
Promise.mapSeries( Iterable<any>|Promise<Iterable<, function(any item, int index, int length) mapper ) -> Promise
和Promise.map,但会按数组顺序依次执行mapper。
3.10 Promise.race - 非Promise对象包成Promise对象
Promise.race(Iterable<any>|Promise<Iterable<) -> Promise
将数组中的非Promise对象,包装成Promise对象。参见ES 6Promise.race方法。
.all - 实例all方法
.all() -> Promise
3.12 .props - 实例props方法
.props() -> Promise
3.13 .any - 实例any方法
.any() -> Promise
3.14 .some - 实例some方法
.some(int count) -> Promise
3.15 .map - 实例map方法
.map(
function(any item, int index, int length) mapper,
[Object {concurrency: int=Infinity} options]
) -> Promise
相当于Promise.map(this, mapper, options)
3.16 .filter - 实例filter方法
.filter(
function(any item, int index, int length) filterer,
[Object {concurrency: int=Infinity} options]
) -> Promise
相当于Promise.filter(this, filterer, options)
3.17 .each - 实例each方法
.each(function(any item, int index, int length) iterator) -> Promise
相当于Promise.each(this, iterator)
3.18 .mapSeries - 实例mapSeries方法
.mapSeries(function(any item, int index, int length) mapper) -> Promise
相当于Promise.mapSeries(this, iterator)
4. 资源管理(Resource management)
在异步操作中,合理的使用和优化资源是非常有难度的。如,对于如下一个操作:
function doStuff() {
return Promise.all([
connectionPool.getConnectionAsync(),
fs.readFileAsync("file.sql", "utf8")
]).spread(function(connection, fileContents) {
return connection.query(fileContents).finally(function() {
connection.close();
});
}).then(function() {
console.log("query successful and connection closed");
});
}
随着操作时间和操作资源的增加,spread可能会耗尽服务器资源,这样就失去了异步编程的优势。
bluebird提供了以下两个方法,让我们合理的优化和释放资源:
.disposer- 为对象资源提供一个包装和释放方法Promise.using- 使用资源,并会自动调用资源的disposer释放方法的函数
var using = Promise.using;
using(
getConnection(),
fs.readFileAsync("file.sql", "utf8"), function(connection, fileContents) {
return connection.query(fileContents);
}).then(function() {
console.log("query successful and connection closed");
});
4.1 .disposer - 添加资源释放器
.disposer(function(any resource, Promise usingOutcomePromise) disposer) -> Disposer
用于资源释放器方法的扩展方法,这个方法将在调用Promise.using时清除资源。
返回一个Disposer对象,该对象封装了资源清理方法。用户可以通过Promise.using获取资源或对资源进行清理。第二个参数是传给资源处理器的promise对象,可以用于同步检查资源。
如:
// 会返回一个promise但是一个Disposer
function getConnection() {
return db.connect().disposer(function(connection, promise) {
connection.close();
});
}
在上面示例中能过getConnection()方法返回的连接,只能通过Promise.using使用,如:
function useConnection(query) {
return Promise.using(getConnection(), function(connection) {
return connection.sendQuery(query).then(function(results) {
return process(results);
})
});
}
4.2 promise.using - 使用资源
Promise.using( Promise|Disposer|any resource, Promise|Disposer|any resource..., function(any resources...) handler ) -> Promise
Promise.using( Array<Promise|Disposer|Any> resources, function(Array<any> resources) handler ) -> Promise
结合.disposer,确保无论任何情况,指定的资源释放器都会在promise回调时调用。
如,可以像下面这样使用多个资源:
using(getConnection(), function(conn1) {
return using(getConnection(), function(conn2) {
// use conn1 and conn 2 here
});
}).then(function() {
// Both connections closed by now
})
5. Promise包装器(Promisification)
官方文档叫做Promisification,意思是将一个没有Promise的API对象包装成有Promise的API对象,即将其Promise化,或者可以理解成Promise包装器。
bluebird中有用于单个函数包装的Promise.promisify方法,也有用于对象属性包装的Promise.promisifyAll方法。
5.1 Promise.promisify - 单个函数对象的Promise化
Promise.promisify(
function(any arguments..., function callback) nodeFunction,
[Object {
multiArgs: boolean=false,
context: any=this
} options]
) -> function
将Node.js对象nodeFunction包装为Promise对象,包装后将使用.then、.catch等Promise方法代替Node.js中的回调。
如,我们可以像下面这样将Node.jsfs模块中的readFile方法包装成一个Promise对象:
var readFile = Promise.promisify(require("fs").readFile);
readFile("myfile.js", "utf8").then(function(contents) {
return eval(contents);
}).then(function(result) {
console.log("The result of evaluating myfile.js", result);
}).catch(SyntaxError, function(e) {
console.log("File had syntax error", e);
//捕获错误
}).catch(function(e) {
console.log("Error reading file", e);
});
5.2 Promise.promisifyAll - 对象属性的Promise化
Promise.promisifyAll(
Object target,
[Object {
suffix: String="Async",
multiArgs: boolean=false,
filter: boolean function(String name, function func, Object target, boolean passesDefaultFilter),
promisifier: function(function originalFunction, function defaultPromisifier)
} options]
) -> Object
将传入的对象实体的属性包装成Promise对象。
如,我们可以fs模块中的所有方法都Promise化:
var fs = Promise.promisifyAll(require("fs"));
fs.readFileAsync("myfile.js", "utf8").then(function(contents) {
console.log(contents);
}).catch(function(e) {
console.error(e.stack);
});
5.3 Promise.fromCallback - 包装为成功状态的Promise
Promise.fromCallback(
function(function callback) resolver,
[Object {multiArgs: boolean=false} options]
) -> Promise
Promise.fromNode(
function(function callback) resolver,
[Object {multiArgs: boolean=false} options]
) -> Promise
从Node.js的callback回调函数中返回一个resolved状态的Promise实例。
使用示例:
var Promise = require("bluebird");
// "email-templates" doesn't expose prototypes for promisification
var emailTemplates = Promise.promisify(require('email-templates'));
var templatesDir = path.join(__dirname, 'templates');
emailTemplates(templatesDir).then(function(template) {
return Promise.fromCallback(function(callback) {
return template("newsletter", callback);
}, {multiArgs: true}).spread(function(html, text) {
console.log(html, text);
});
});
也可以用于Function.prototype.bind:
var Promise = require("bluebird");
// "email-templates" doesn't expose prototypes for promisification
var emailTemplates = Promise.promisify(require('email-templates'));
var templatesDir = path.join(__dirname, 'templates');
emailTemplates(templatesDir).then(function(template) {
return Promise.fromCallback(template.bind(null, "newsletter"), {multiArgs: true})
.spread(function(html, text) {
console.log(html, text);
});
});
5.4 Promise.asCallback - Promise对象的callback化
.asCallback(
[function(any error, any value) callback],
[Object {spread: boolean=false} options]
) -> this
.nodeify(
[function(any error, any value) callback],
[Object {spread: boolean=false} options]
) -> this
为Promise实例注册Node.js式的callback回调
如,对于如下一个Promise实例注册为Node.js的回调式:
function getDataFor(input, callback) {
return dataFromDataBase(input).asCallback(callback);
}
我们会像这样使用这个Promise实例:
getDataFor("me").then(function(dataForMe) {
console.log(dataForMe);
});
但将其回调化后,就可以像下面这样使用:
getDataFor("me", function(err, dataForMe) {
if( err ) {
console.error( err );
}
console.log(dataForMe);
});
6. 定时器
用于promise延时和超时的方法
6.1 Promise.delay - 延时执行
Promise.delay( int ms, [any|Promise<any> value=undefined] ) -> Promise
将指定的Promise对象value延时ms毫秒后执行
Promise.delay(500).then(function() {
console.log("500 ms passed");
return "Hello world";
}).delay(500).then(function(helloWorldString) {
console.log(helloWorldString);
console.log("another 500 ms passed") ;
});
6.2 .delay - 实例延时执行
.delay(int ms) -> Promise
6.3 .timeout - 实例超时
.timeout( int ms, [String message="operation timed out"] ) -> Promise
.timeout( int ms, [Error error] ) -> Promise
返回一个在指定时间ms后变为失败状态的promise。
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));
fs.readFileAsync("huge-file.txt").timeout(100).then(function(fileContents) {
// 执行成功的一些操作
}).catch(Promise.TimeoutError, function(e) {
console.log("could not read file within 100ms");
});
7. 工具方法(utility)
可能会用到的一些工具方法
7.1 .tap - 非失败状态调用
.tap(function(any value) handler) -> Promise
类似.finally,但只有在非失败状态被调用
getUser().tap(function(user) {
//Like in finally, if you return a promise from the handler
//the promise is awaited for before passing the original value through
return recordStatsAsync();
}).then(function(user) {
//user is the user from getUser(), not recordStatsAsync()
});
7.2 .call - call方法
.call( String methodName, [any args...] )
一个便捷的call方法。
promise.then(function(obj) {
return obj[methodName].call(obj, arg...);
});
如,将some做为Array对象的内置方法:
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));
var path = require("path");
var thisPath = process.argv[2] || ".";
var now = Date.now();
fs.readdirAsync(thisPath)
.map(function(fileName) {
return fs.statAsync(path.join(thisPath, fileName));
})
.call("some", function(stat) {
return (now - new Date(stat.mtime)) < 10000;
})
.then(function(someFilesHaveBeenModifiedLessThanTenSecondsAgo) {
console.log(someFilesHaveBeenModifiedLessThanTenSecondsAgo);
});
7.3 .get - 获取属性值
便捷的属性访问器方法
promise.then(function(obj) {
return obj[propertyName];
});
7.4 .return - 返回一个值
.return(any value) -> Promise
.thenReturn(any value) -> Promise
便捷的属性访问器方法
.then(function() {
return value;
});
如,可以像下面这样返回执行成功后的值:
function getData() {
var data;
return query().then(function(result) {
data = result;
}).return(data);
}
7.5 .throw - 抛出异常
.throw(any reason) -> Promise
.thenThrow(any reason) -> Promise
可以像下面这样使用:
.then(function() {
throw reason;
});
7.6 .catchReturn - 捕获异常并返回一个值
.catchReturn( [class ErrorClass|function(any error) predicate], any value ) -> Promise
使用方法如下:
.catch(function() {
return value;
});
7.7 .catchThrow - 捕获并抛出异常
.catchThrow( [class ErrorClass|function(any error) predicate], any reason ) -> Promise
使用方法如下:
.catch(function() {
throw reason;
});
7.8 .reflect - 返回总是成功状态的promise
.reflect() -> Promise<PromiseInspection>
使用方法如下:
总是返回一个成功状态的promise实例
var object = {
first: getPromise1(),
second: getPromise2()
};
Promise.props(Object.keys(object).reduce(function(newObject, key) {
newObject[key] = object[key].reflect();
return newObject;
}, {})).then(function(object) {
if (object.first.isFulfilled()) {
console.log("first was fulfilled with", object.first.value());
} else {
console.error("first was rejected with", object.first.reason());
}
})
7.9 Promise.noConflict - 解决浏览器环境的命名冲突
Promise.noConflict() -> Object
用于解决览器环境的命名空间冲突
使用方法如下:
<!-- 另一个 promise 库首先被加载 --> <script type="text/javascript" src="/scripts/other_promise.js"></script> <script type="text/javascript" src="/scripts/bluebird_debug.js"></script> <script type="text/javascript"> //Release control right after var Bluebird = Promise.noConflict(); // 从另一个promise库中返回 Bluebird命名空间: var promise = Bluebird.resolve(new Promise()); </script>
7.10 Promise.noConflict - 调度设置
Promise.setScheduler(function(function fn) scheduler) -> function
设置一个在异步调度中使用的函数。
Promise.setScheduler(function(fn) {
setTimeout(fn, 0);
});
