https://itbilu.com/nodejs/npm/VJHw6ScNb.html#api-promise.try
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对象 - <a href="https://itbilu.com/nodejs/npm/VJHw6ScNb.html#api-all" 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://itbilu.com') .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
数组或Iterable
promise,执行成功指定次数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
数组或Iterable
promise,执行一个处理函数mapper
并返回执行后的数组或Iterable
promise。
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
数组或Iterable
promise,执行一个处理函数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
数组或Iterable
promise,执行一个过滤函数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
数组或Iterable
promise,执行一个函数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); });