Javascript 除非全局声明变量,否则无法从事件处理程序中的函数更新变量

Javascript 除非全局声明变量,否则无法从事件处理程序中的函数更新变量,javascript,node.js,mongoose,scope,socket.io,Javascript,Node.js,Mongoose,Scope,Socket.io,我有一个nodejs后端应用程序,它利用mongoose进行数据库连接和查询,在本例中,它在socket.io的事件处理程序中执行,即 io.on(“连接”,[callback]) 但是,每当我在io.on(“连接”)的事件处理程序中运行查询时,比如socket.on(“myEvent”,[callback])我在更新后一个事件处理程序中的变量时都会遇到问题,特别是当它是mongoose查询的回调时 对于某些上下文,以下是我尝试运行的示例: io.on("connection", functio

我有一个nodejs后端应用程序,它利用mongoose进行数据库连接和查询,在本例中,它在socket.io的事件处理程序中执行,即
io.on(“连接”,[callback])

但是,每当我在
io.on(“连接”)
的事件处理程序中运行查询时,比如
socket.on(“myEvent”,[callback])
我在更新后一个事件处理程序中的变量时都会遇到问题,特别是当它是mongoose查询的回调时

对于某些上下文,以下是我尝试运行的示例:

io.on("connection", function(socket) {
  var myVar; // declare user within event handler scope
  socket.on("myEvent", function(m) {
    var query = m.myQuery;
    User.findOne({query}, function(err, doc) {
    if (err) {
      // error handling
    } else {
      myVar = doc;
      console.log(myVar); // logs whole document as it should
    }
  });

  socket.on("myOtherEvent", function(m){
    console.log(myVar); // undefined!?
  });
});
我还尝试在自己的函数上使用自定义回调来解决这个问题,该函数运行相同的查询并返回文档,因为我认为这可能是由于db查询是异步的——但是,这种方法也不起作用

此外,我还尝试在
socket.on(“myEvent”)
方法中使用(显然臭名昭著的)
var=this
方法,希望它能够引用原始回调。这方面也没有运气

要么我错过了猫鼬的全部要点,要么我快发疯了;我会感激你的帮助

编辑:如前所述,只要我全局声明
myVar
,变量就会在所述mongoose查询的
else
块中更新。然后我也可以通过另一个
socket.on
处理程序访问它

我应该在
socket.on(“连接”)
块中声明我的变量吗?它保持不变,例如,如果在声明
myVar=“为什么不起作用?”之后我
console.log(myVar)
?!“
套接字中。在(“myOtherEvent”)
上,它实际上记录了
“为什么不工作?!”?!“
到控制台

编辑2:此处描述了一个非常类似的问题:

但是,使用
myVar=myVar | |{}
的解决方案不起作用

编辑3:正如建议的那样,我在查询中使用了(在本例中为ES6)承诺,我更新的查询(仍然在
套接字中。在
上,只是没有显示在这里)看起来像我基于它制作的以下示例:

User.findOne({query}).exec().then(function(doc) {
    if (!doc) {
        myVar = null; // unrelated
        logger.debug("Couldnt find user!"); // unrelated
    } else {
        myVar = doc;
        logger.debug(doc); // correctly prints the whole document
        logger.debug(user); // also correctly prints whole document
    }
}).catch(function(err){
    logger.error("Error searching for query: " + err);// unrelated
});
目前,如果我以后尝试访问
myVar
(在查询完成并将文档打印到控制台后,
else
-块中),它仍然会打印出我给它的初始值。无论是null、bool还是字符串,它都保持不变


但是:有趣的是,如果我全局声明它,它会开始更新变量-但是,它不是套接字独有的,这就是为什么这种方法无法解决这个特定问题的原因。

最初由@Bergi解决-谢谢!

对于任何新来者或不知道(如我所知)套接字连接无法合并的人:

与此问题特别相关的是,Socket.io创建多个实例/处理程序——具体来说,每个套接字一个。 这意味着拥有多个套接字连接将使用所述事件处理程序创建多个实例,这也会导致这些变量的多个实例

例如,如果您出于任何原因希望具有特定于每个套接字连接的局部作用域变量,那么这也非常有用


谢谢!

在第二个套接字中,事件
myVar
未定义,因为第一个事件中发生了一些异步事件。如果您需要在第二个事件中访问第一个事件中的数据,为什么不将第二个事件侦听器放入查询的成功回调中?您还可以查看生成器函数或异步/等待以摆脱回调地狱:)1)您如何推断变量在全局声明时会正确更新?您是否仅根据
console.log(myVar)来判断
products?如果是这样,这可能只是一种“错觉”,因为浏览器内部延迟了实际的打印输出,导致打印的内容不一定是调用
console.log
时对象的状态。换句话说,变量可能没有如您预期的那样实际更新,它只是看起来是这样的。在这种情况下,全局或本地不应该有什么区别。请尝试使用
控制台进行日志记录。改为使用log(typeof myVar)
。2)是什么触发了“myoterevent”事件,以及如何确保在调用
用户.findOne
函数(即更新
myVar
)之前不会触发该事件已被调用?您能显示用于测试的客户端代码吗?我猜是a)您等待查询完成的时间不够长,或者b)您实际打开了不同的连接,并从另一个连接收到了第二个事件。@Ghost我意识到我在无法再编辑注释后错误地引用了浏览器,b但是我写的关于
console.log
的内容在Node中也适用。它是延迟的,这意味着它打印出来的内容不能保证是对象在传递到
console.log
时的实际样子。然而,我认为Bergi在这里通过“交叉触发”事件解决了真正的问题,这就解释了它工作的原因作用域变量和全局属性之间存在差异。