将参数传递给 Javascript/NodeJs 中的预定义回调

Passing parameters to predefined callbacks in Javascript/NodeJs

我正在尝试使用 bcrypt 扩展 NodeJs 后端的简单登录方法。我的问题是我现在需要通过散列步骤传递 user 变量。我当前的方法是这样的——当然 useronPasswordHashed:

的范围内是未定义的
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
      }
    },
    ...
  );
},

原则上我可以: (a) 使用bcrypt的同步调用。但是,在某些时候我可能会遇到相同的问题,即没有可用的同步函数调用。 (b) 我可以先定义var userObj = null,然后在onResultReceived方法中设置userObj = useruserObj 然后应该在所有范围内可见。但这似乎不是最佳做法。或者是吗?

从目前的阅读来看,使用 bind() 似乎是可行的方法。我只是不明白如何将它应用到我的。例如:

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

不起作用。我不知道 step 包是否会在这里引起任何问题。处理回调链非常方便。

编辑:step 包文档的链接:npm, github

根据我的发现和测试,我可以覆盖回调,例如:

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

但有了这个,我当然会丢失有关 errorhash 的信息。

您可以使用可以直接访问父范围内变量的内联匿名回调,您可以使用 .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);
      }
    },
    ...
  );
},

仅供参考,如果您提供一些信息或 link 来记录 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);
      }
    },
    ...
  );
},