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

javascript - How to pass a third argument to a callback using Bluebird.js nodeify - Stack Overflow

programmeradmin1浏览0评论

With a little help I've arrived at the following code to promisify a passport.js login strategy.

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var Promise = require('bluebird');
var bcrypt = require('bcrypt');
var db = require('./db').db; //users are stored in mongo

//I'm using bluebird.js for promises
var users = Promise.promisifyAll(db.users);
var pare = Promise.promisify(bcryptpare);


// This strategy is used by passport to handle logins
module.exports.localStrategy = new LocalStrategy(function(username, password, done) {
  users.findOneAsync({username: username}).bind({})
    .then(function(user) {
        if (!user) {
          throw new NoMatchedUserError('Incorrect username.');
          //should be equivalent to:
          // return done(null, false, {message:'something'});
        }
        this.user = user;
        return pare(password, user.password);
    })
    .then(function(isMatch) {
      if (isMatch) {
        return this.user;
        //is equivalent to:
        // return done(null, this.user);
      }
      else {
        throw { message: 'Incorrect password.' };
        //should be equivalent to:
        // return done(null, false, {message:'something else'};
      }
    })
    .nodeify(done);
});

by calling nodeify(done) I can handle the path where passwords match but I don't know how to pass the optional third parameter out so that passport.js can use it.

Is it possible to have the two failure (not error) paths handled?


Update:

As asked in the ments I created an issue on Github and this feature was (very promptly) added in Bluebird v2.0

With a little help I've arrived at the following code to promisify a passport.js login strategy.

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var Promise = require('bluebird');
var bcrypt = require('bcrypt');
var db = require('./db').db; //users are stored in mongo

//I'm using bluebird.js for promises
var users = Promise.promisifyAll(db.users);
var pare = Promise.promisify(bcrypt.pare);


// This strategy is used by passport to handle logins
module.exports.localStrategy = new LocalStrategy(function(username, password, done) {
  users.findOneAsync({username: username}).bind({})
    .then(function(user) {
        if (!user) {
          throw new NoMatchedUserError('Incorrect username.');
          //should be equivalent to:
          // return done(null, false, {message:'something'});
        }
        this.user = user;
        return pare(password, user.password);
    })
    .then(function(isMatch) {
      if (isMatch) {
        return this.user;
        //is equivalent to:
        // return done(null, this.user);
      }
      else {
        throw { message: 'Incorrect password.' };
        //should be equivalent to:
        // return done(null, false, {message:'something else'};
      }
    })
    .nodeify(done);
});

by calling nodeify(done) I can handle the path where passwords match but I don't know how to pass the optional third parameter out so that passport.js can use it.

Is it possible to have the two failure (not error) paths handled?


Update:

As asked in the ments I created an issue on Github and this feature was (very promptly) added in Bluebird v2.0

https://github./petkaantonov/bluebird/issues/219

Share Improve this question edited Apr 13, 2017 at 12:40 CommunityBot 11 silver badge asked May 28, 2014 at 19:48 Paul D'AmbraPaul D'Ambra 7,8143 gold badges55 silver badges98 bronze badges 7
  • Wow, that's actually a pretty good use case for nodeify, plenty of node APIs need more than one parameter. Open an issue, we'll entertain it (meaning, I'll bug petka until he writes it, and if he won't I'll write it and he'll rewrite it for performance)ץ – Benjamin Gruenbaum Commented May 28, 2014 at 19:55
  • Uh, your original code looked quite fine actually. You would need a promise that could resolve to three possible states: Error, User identified, and Login Problem. You might try different error types that are handled differently, but you cannot simply use nodeify here. – Bergi Commented May 28, 2014 at 20:00
  • @BenjaminGruenbaum I don't see how it's possible, if you resolve the promise with an array, how do you know whether nodeify should call it with the array as result or spreading the array for the nodeback? Passport is violating node callback convention here and look at the result :P – Esailija Commented May 29, 2014 at 11:08
  • @Esailija one solution would be a second parameter. – Benjamin Gruenbaum Commented May 29, 2014 at 11:09
  • @BenjaminGruenbaum sounds like a foot gun – Esailija Commented May 29, 2014 at 11:10
 |  Show 2 more ments

3 Answers 3

Reset to default 4

Use:

.nodeify(done, {spread: true});

This allows multiple arguments to be passed to the 'done' callback.

More info on:

Bluebird nodeify documentation

I'm adding this answer to show how to use .nodeify(done, {spread: true}) (as mentioned in other answers/ments) with the original example.

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var Promise = require('bluebird');
var bcrypt = require('bcrypt');
var db = require('./db').db; //users are stored in mongo

//I'm using bluebird.js for promises
var users = Promise.promisifyAll(db.users);
var pare = Promise.promisify(bcrypt.pare);

// This strategy is used by passport to handle logins
module.exports.localStrategy = new LocalStrategy(function(username, password, done) {
  users.findOneAsync({username: username}).bind({})
    .then(function(user) {
        if (!user) {
          return [false, { message: 'Incorrect username.' }]; <---------------
          //should be equivalent to:
          // return done(null, false, {message:'something'});
        }
        this.user = user;
        return pare(password, user.password);
    })
    .then(function(isMatch) {
      if (isMatch) {
        return this.user;
        //is equivalent to:
        // return done(null, this.user);
      }
      else {
        return [false, { message: 'Incorrect password.' }]; <---------------
        //should be equivalent to:
        // return done(null, false, {message:'something else'};
      }
    })
    .nodeify(done, {spread: true});
});

Currently, there is no way to do it with .nodeify, you can of course do it manually with .then:

.then(function(result){
     done(/*whatever arguments you need*/);
},function(failure){
     done(/* failure argumnets */);
});
发布评论

评论列表(0)

  1. 暂无评论