如何确保 "this" 与 Promise.promisify 正确?
How to ensure correct "this" with Promise.promisify?
我正在尝试使用 Bluebird 库的承诺来重构我的 nodejs 服务器,但我遇到了一个简单的问题。
从我的数据库中获取用户后,我想列出与该用户关联的所有通知 class:
糟糕的方式(工作...)
adapter.getUsers(function(users){
users.rows.forEach(function(item){
user = item.username;
adapter.getNotifications(user, function(notificationList){
console.log(notificationList);
})
});
});
优雅的尝试方式(不工作...)
var getNotifications = Promise.promisify(adapter.getNotifications);
adapter.getUsers().then(function(users) {
users.rows.forEach(function(item){
var dbUser = "sigalei/" + item.value.name;
console.log(dbUser);
return getNotifications(dbUser);
});
}).then(function(result){
console.log(result);
console.log("NOTIFICATIONLIST");
});
然而,当我执行这段代码时,我在 getNotification 方法中遇到了这个错误:
Unhandled rejection TypeError: Cannot read property 'nano' of undefined
at Adapter.getNotifications (/Users/DaniloOliveira/Workspace/sigalei-api/api/tools/couchdb-adapter.js:387:30)
at tryCatcher (/Users/DaniloOliveira/Workspace/sigalei-api/node_modules/bluebird/js/main/util.js:26:23)
编辑
在 user2864740 的宝贵评论之后,我注意到该错误与某些范围问题有关。那么,为什么在使用 promisify 方法之后,方法 getNotifications 无法识别 "this" env 变量?
var Adapter = module.exports = function(config) {
this.nano = require('nano')({
url: url,
request_defaults: config.request_defaults
});
};
Adapter.prototype.getNotifications = function(userDb, done) {
var that = this;
console.log(that);
var userDbInstance = that.nano.use(userDb);
userDbInstance.view('_notificacao', 'lista',
{start_key: "[false]", end_key: "[false,{}]"},
function(err, body) {
if(err){ done(err); }
done(body);
});
};
简单的怎么样
var getNotifications = Promise.promisify(adapter.getNotifications.bind(adapter));
或者可能
var getNotifications = Promise.promisify(function () {
return adapter.getNotifications.apply(adapter, arguments);
});
?
我不确定我是否理解你的问题,但这应该确保 this
被绑定而不是 undefined
当你做 return getNotifications(dbUser);
这只是很常见的problem of calling "unbound" methods。
您可以将上下文作为选项传递给 Promise.promisify
以使其绑定:
var getNotifications = Promise.promisify(adapter.getNotifications, {context: adapter});
或者,您需要 .bind()
方法,或在 adapter
上调用新的 getNotifications
函数(使用 .call()
)。您也可以考虑使用 Promise.promisifyAll(adapater)
然后调用 adapter.getNotificationsAsync(…)
.
请注意,这仍然不起作用。您不能简单地在循环中创建承诺 - 您需要显式等待它们并且 return 来自 then
回调的承诺,否则只有 undefined
您 returned 的值立即传递给下一个回调。
adapter.getUsers().then(function(users) {
return Promise.all(users.rows.map(function(item){
var dbUser = "sigalei/" + item.value.name;
console.log(dbUser);
return getNotifications(dbUser);
}));
}).then(function(results) {
for (var i=0; i<results.length; i++)
console.log("result:", results[i]);
});
除了 Promise.all(users.rows.map(…))
,在 Bluebird 中您还可以使用 Promise.map(users.rows, …)
。
我正在尝试使用 Bluebird 库的承诺来重构我的 nodejs 服务器,但我遇到了一个简单的问题。
从我的数据库中获取用户后,我想列出与该用户关联的所有通知 class:
糟糕的方式(工作...)
adapter.getUsers(function(users){
users.rows.forEach(function(item){
user = item.username;
adapter.getNotifications(user, function(notificationList){
console.log(notificationList);
})
});
});
优雅的尝试方式(不工作...)
var getNotifications = Promise.promisify(adapter.getNotifications);
adapter.getUsers().then(function(users) {
users.rows.forEach(function(item){
var dbUser = "sigalei/" + item.value.name;
console.log(dbUser);
return getNotifications(dbUser);
});
}).then(function(result){
console.log(result);
console.log("NOTIFICATIONLIST");
});
然而,当我执行这段代码时,我在 getNotification 方法中遇到了这个错误:
Unhandled rejection TypeError: Cannot read property 'nano' of undefined at Adapter.getNotifications (/Users/DaniloOliveira/Workspace/sigalei-api/api/tools/couchdb-adapter.js:387:30) at tryCatcher (/Users/DaniloOliveira/Workspace/sigalei-api/node_modules/bluebird/js/main/util.js:26:23)
编辑
在 user2864740 的宝贵评论之后,我注意到该错误与某些范围问题有关。那么,为什么在使用 promisify 方法之后,方法 getNotifications 无法识别 "this" env 变量?
var Adapter = module.exports = function(config) {
this.nano = require('nano')({
url: url,
request_defaults: config.request_defaults
});
};
Adapter.prototype.getNotifications = function(userDb, done) {
var that = this;
console.log(that);
var userDbInstance = that.nano.use(userDb);
userDbInstance.view('_notificacao', 'lista',
{start_key: "[false]", end_key: "[false,{}]"},
function(err, body) {
if(err){ done(err); }
done(body);
});
};
简单的怎么样
var getNotifications = Promise.promisify(adapter.getNotifications.bind(adapter));
或者可能
var getNotifications = Promise.promisify(function () {
return adapter.getNotifications.apply(adapter, arguments);
});
?
我不确定我是否理解你的问题,但这应该确保 this
被绑定而不是 undefined
当你做 return getNotifications(dbUser);
这只是很常见的problem of calling "unbound" methods。
您可以将上下文作为选项传递给 Promise.promisify
以使其绑定:
var getNotifications = Promise.promisify(adapter.getNotifications, {context: adapter});
或者,您需要 .bind()
方法,或在 adapter
上调用新的 getNotifications
函数(使用 .call()
)。您也可以考虑使用 Promise.promisifyAll(adapater)
然后调用 adapter.getNotificationsAsync(…)
.
请注意,这仍然不起作用。您不能简单地在循环中创建承诺 - 您需要显式等待它们并且 return 来自 then
回调的承诺,否则只有 undefined
您 returned 的值立即传递给下一个回调。
adapter.getUsers().then(function(users) {
return Promise.all(users.rows.map(function(item){
var dbUser = "sigalei/" + item.value.name;
console.log(dbUser);
return getNotifications(dbUser);
}));
}).then(function(results) {
for (var i=0; i<results.length; i++)
console.log("result:", results[i]);
});
除了 Promise.all(users.rows.map(…))
,在 Bluebird 中您还可以使用 Promise.map(users.rows, …)
。