最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to ensure correct "this" with Promise.promisify? - Stack Overflow

programmeradmin0浏览0评论

I am trying to refactory my nodejs server using promises with Bluebird library, but I am stuck in a simple problem.

After to get the users from my db, I want to list all notification class associated with this user:

Bad Way (working...)

adapter.getUsers(function(users){
    users.rows.forEach(function(item){
        user = item.username;
        adapter.getNotifications(user, function(notificationList){
            console.log(notificationList);
        })
    });
});

Elegant Tentative Way (not working...)

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");
});

However when I execute this code I get this error inside my getNotification method:

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)

EDIT

After the user2864740`s precious ments, I noticed that the error is related with some scope problem. So, why after to use promisify method, the method dont getNotifications recognize the "this" env variable?

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);
    });

};

I am trying to refactory my nodejs server using promises with Bluebird library, but I am stuck in a simple problem.

After to get the users from my db, I want to list all notification class associated with this user:

Bad Way (working...)

adapter.getUsers(function(users){
    users.rows.forEach(function(item){
        user = item.username;
        adapter.getNotifications(user, function(notificationList){
            console.log(notificationList);
        })
    });
});

Elegant Tentative Way (not working...)

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");
});

However when I execute this code I get this error inside my getNotification method:

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)

EDIT

After the user2864740`s precious ments, I noticed that the error is related with some scope problem. So, why after to use promisify method, the method dont getNotifications recognize the "this" env variable?

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);
    });

};
Share Improve this question edited Sep 10, 2015 at 19:54 user2864740 62.1k15 gold badges158 silver badges227 bronze badges asked Sep 10, 2015 at 19:11 Danilo OliveiraDanilo Oliveira 2802 silver badges12 bronze badges 3
  • Hey, the error is generated inside the getNotifications method that is being "promisify". – Danilo Oliveira Commented Sep 10, 2015 at 19:25
  • @user2864740 Again, I edited the question, I think that the problem is related with scope variables... – Danilo Oliveira Commented Sep 10, 2015 at 19:39
  • Try .call()ing it with the adapteras the this. – Amit Commented Sep 10, 2015 at 19:45
Add a ment  | 

2 Answers 2

Reset to default 7

This is just the very mon problem of calling "unbound" methods.
You can pass the context as an option to Promise.promisify to have it bound:

var getNotifications = Promise.promisify(adapter.getNotifications, {context: adapter});

Alternatively, you'd need to .bind() the method, or call the new getNotifications function on the adapter (using .call()). You might also consider using Promise.promisifyAll(adapater) and then just calling adapter.getNotificationsAsync(…).

Notice that this still doesn't work. You cannot simply create promises in a loop - you need to await them explicitly and return a promise from the then callback, otherwise just the undefined value you returned will be passed to the next callback immediately.

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]);
});

Instead of Promise.all(users.rows.map(…)), in Bluebird you can also use Promise.map(users.rows, …).

What about simply

var getNotifications = Promise.promisify(adapter.getNotifications.bind(adapter));

or possibly

var getNotifications = Promise.promisify(function () {
    return adapter.getNotifications.apply(adapter, arguments);
});

?

I'm not sure I understand your problem well, but this should make sure this is bound and not undefined when you do return getNotifications(dbUser);

发布评论

评论列表(0)

  1. 暂无评论