2015-11-06 3 views
1

Я пытаюсь расширить мой простой метод signin для бэкэнд NodeJs с помощью bcrypt. Моя проблема в том, что теперь мне нужно передать переменную user через шаг хэширования. Мой текущий метод выглядит так - и, естественно, user не определен в рамках onPasswordHashed:Передача параметров на предопределенные обратные вызовы в Javascript/NodeJs

signin : function(req, res, next) { 
    step (
    function findUser() { 
     User.findOne({ "email": req.body.email }, this); 
    }, 
    function onResultReceived(error, user) { 
     if (error) { 
     ... 
     } else { 
     if (user) { 
      bcrypt.compare(req.body.password, user.password, this); 
     } else { 
      ... 
     } 
     }  
    }, 
    function onPasswordHashed(error, hash) { 
     if (error) { 
     ... 
     } else { 
     bcrypt.compare(user.password, hash, this); // user is undefined here 
     } 
    }, 
    ... 
); 
}, 

В принципе я могу: (а) использовать синхронный вызов bcrypt. Однако в какой-то момент я могу столкнуться с той же проблемой, при которой нет синхронного вызова функции. (b) Сначала я могу определить var userObj = null и установить его userObj = user в методе onResultReceived. userObj должен быть видимым во всех областях. Но это не кажется лучшей практикой. Или это?

От чтения до сих пор, используя bind(), кажется, путь. Я просто не понимаю, как применить его к моему. Например:

bcrypt.compare(req.body.password, user.password, this.bind({user: user})); 

не работает. Я не знаю, может ли пакет step вызвать какие-либо проблемы. Просто очень удобно обрабатывать цепочки обратных вызовов.

EDIT: Ссылки на step пакет документации: npm, github

Из того, что я нашел и испытанные, я могу переписать функцию обратного вызова, например:

bcrypt.compare(req.body.password, user.password, this(user)); 

Но с этим я, конечно, свободной информации о error и hash.

ответ

1

Вы можете использовать встроенный анонимный обратный вызов, который может непосредственно получить доступ к переменному в родительской сфере вы можете использовать .bind() добавить аргументы обратного вызова или в вашем конкретном случае последовательности, вы можете сохранить user объект в более контекстный переменный поэтому он доступен для последующих обратных вызовов. См переменной localUser в этом примере:

signin : function(req, res, next) { 
    var localUser; 
    step (
    function findUser() { 
     User.findOne({ "email": req.body.email }, this); 
    }, 
    function onResultReceived(error, user) { 
     // save user variable to higher scoped variable so 
     // subsequent callbacks can access it 
     localUser = user; 
     if (error) { 
     ... 
     } else { 
     if (user) { 
      bcrypt.compare(req.body.password, user.password, this); 
     } else { 
      ... 
     } 
     }  
    }, 
    function onPasswordHashed(error, hash) { 
     if (error) { 
     ... 
     } else { 
     // use localUser from higher scope here that was set by a previous 
     // step in the process 
     bcrypt.compare(localUser.password, hash, this); 
     } 
    }, 
    ... 
); 
}, 

FYI, если вы предоставить некоторую информацию или ссылку на документ о том, как работает функция step(), может быть также способом передачи данных от одного шага на следующие шаги.


Предполагая, что функция step() происходит от this module, вы также можете сделать это следующим образом:

signin : function(req, res, next) { 
    step (
    function findUser() { 
     User.findOne({ "email": req.body.email }, this); 
    }, 
    function onResultReceived(error, user) { 
     // save user on our stepper object so it can be accessed by later callbacks 
     this.user = user; 
     if (error) { 
     ... 
     } else { 
     if (user) { 
      bcrypt.compare(req.body.password, user.password, this); 
     } else { 
      ... 
     } 
     }  
    }, 
    function onPasswordHashed(error, hash) { 
     if (error) { 
     ... 
     } else { 
     // use this.user that was set by a previous 
     // step in the process 
     bcrypt.compare(this.user, hash, this); 
     } 
    }, 
    ... 
); 
}, 

Значение this, переданное в каждый последующий обратный вызов является общей функцией объект, который вы можете прикрепить собственные свойства. Хотя этот вид кажется более чистым, чем предыдущая, на самом деле это немного опаснее, поскольку свойства, добавляемые к объекту this, могут противоречить вещам, используемым во внутренней реализации функции step(). Первый вариант (объект в родительской области) полностью закрыт и не будет иметь возможного конфликта.


Теперь понимание о том, как step() работает, вы можете использовать .bind() добавить user объект следующих аргументов обратного вызова, как это:

signin : function(req, res, next) { 
    step (
    function findUser() { 
     User.findOne({ "email": req.body.email }, this); 
    }, 
    function onResultReceived(error, user) { 
     // save user on our stepper object so it can be accessed by later callbacks 
     if (error) { 
     ... 
     } else { 
     if (user) { 
      // prepend user to the callback arguments for the next callback 
      bcrypt.compare(req.body.password, user.password, this.bind(this, user)); 
     } else { 
      ... 
     } 
     }  
    }, 
    function onPasswordHashed(user, error, hash) { 
     // user is passed in here from previous callback 
     if (error) { 
     ... 
     } else { 
     // use this.user that was set by a previous 
     // step in the process 
     bcrypt.compare(user, hash, this); 
     } 
    }, 
    ... 
); 
}, 
+0

Да, используя что-то вроде 'localUser' отражает мой альтернативный метод (б) в моем первоначальном вопросе. Я просто не был уверен, что это правильный способ. Но вы правы, я должен проверить документацию «step». Я надеялся, что смогу связать «пользователь» простым способом. – Christian

+1

@Christian - в вашем конкретном случае вы не можете использовать '.bind()' для передачи 'user', потому что все обратные вызовы должны быть переданы в' step() 'до того, как все были запущены, так что объект' user' в то время неизвестно. Таким образом, альтернативы состоят в том, чтобы сохранить его в более высокой области видимости или передать объект через каждый обратный вызов с помощью функции «step()» и просто добавить свойства к этому объекту, поскольку каждая функция выполняет их доступность для всех последующих обратных вызовов , – jfriend00

+0

«... или передать объект каждому обратному вызову через функциональность step() ...» - можете ли вы прояснить, как это работает, возможно, продлевая ваш ответ. В любом случае, я в порядке с более высокой переменной сферы. Я просто не знал, является ли это «правильным» способом и может вызвать любые побочные эффекты. – Christian

Смежные вопросы