我如何正确编写一个模块来与Bluebird的PromisifyAll兼容
比方说,在node.js模块moduleA.js
,我有以下一些节点式asynchronous函数:
// moduleA.js var init = function (data, callback) { return callback(null, data.params ); }; var delay = function(data, callback) { setTimeout(function(){ callback(null, data); }, 1000*3); } var reverse = function(data, callback) { var j, d = {}; for(j in data) { d[ data[j] ] = j; } callback(null, d); } module.exports = { init: init, delay: delay, reverse: reverse };
我在main.js
使用moduleA.js
,并且可以单独地成功promisify
每个方法,如:
// main.js var Promise = require('bluebird'), modA = require('./moduleA') ); var data = { "a": "one", "b": "two", "c": "three", "d": "four" }; Promise.promisify(modA.init)(data) .then( Promise.promisify(modA.delay) ) .then( Promise.promisify(modA.reverse) ) .then(function(data){ res.send(data); }).catch(function(e){ next(e); });
上面的代码工作得很好,但比所需的更详细。
我的问题是,我将如何修改我的模块,以允许Promise.promisifyAll
在整个导出的对象上正常工作? 我想避免模块内部的promisification
,并允许其他人在消费时select性的promisify
。
我没有成功尝试以下的许多变化:
// main.js var Promise = require('bluebird'), modA = require('./moduleA') ), modAPromised = Promise.promisifyAll(modA); var data = { "a": "one", "b": "two", "c": "three", "d": "four" }; modAPromised.initAsync(data) .then(modAPromised.delayAsync) .then(modAPromised.reverseAsync) .then(function(data){ res.send(data); }).catch(function(e){ next(e); });
当我这样做,我得到和错误,说Cannot call method 'delay' of undefined
。 Promise.promisifyAll
正在按照预期添加所有Async
函数:
// console.log(modAPromised); { init: [Function], delay: [Function], reverse: [Function], initAsync: { [Function] __isPromisified__: true }, delayAsync: { [Function] __isPromisified__: true }, reverseAsync: { [Function] __isPromisified__: true } }
但是我觉得有些东西是与上下文矛盾的。 看来,内部的delayAsync
试图调用this.delay
但这是未定义的。
那么,如何修改我的模块以允许Promise.promisifyAll
在整个导出的对象上正常工作?
提前致谢。
promisifyAll
创build依赖于this
方法,因为当你将一个类的原型传递给它时, this
是不知道的。
例如:
Promise.promisifyAll(require("redis")); // In another file var redis = require("redis"); var client1 = redis.createClient(...); var client2 = redis.createClient(...); client1.putAsync(...); client2.putAsync(...);
当"redis"
被promisified时,没有什么可以绑定的,而这些方法依赖于特定的client
实例。 .putAsync
不能直接调用put
– 它需要调用put
在client1
和putAsync
的上下文中,具体取决于如何putAsync
。
有人提出了一个解决scheme,但他从来没有回应: https : //github.com/petkaantonov/bluebird/issues/470 。
你的模块可以实现为使用nodeify的双重API,这样消费者甚至不需要promisification:
var init = function (data, callback) { return Promise.resolve(data.params).nodeify(callback); }; var delay = function(data, callback) { return Promise.delay(data, 1000 * 3).nodeify(callback); } var reverse = function(data, callback) { var j, d = {}; for(j in data) { d[ data[j] ] = j; } return Promise.resolve(d).nodeify(callback); }
你的问题less于moduleA.js
,在main.js
使用main.js
。
如果您在.then .then()
语句中显式调用promisified函数,则模块将正常工作:
// main.js var Promise = require('bluebird'), modA = require('./moduleA'), modAPromised = Promise.promisifyAll(modA); var data = { "a": "one", "b": "two", "c": "three", "d": "four" }; modAPromised.initAsync(data) .then(function(data) { return modAPromised.delayAsync(data); }) .then(function(data) { return modAPromised.reverseAsync(data); }) .then(function(data){ res.send(data); }).catch(function(e){ next(e); });
至于这是为什么 ,我真的不知道。 我有一个强烈的怀疑promisifyAll
做一些背景约束, promise
不会做。 这可以解释为什么用干净的函数包装你的方法可以解决这个问题。
我相信Bluebird的维护者会知道更多,如果你想得到具体的实施。