Javascript &引用;无法读取未定义的属性";即使在自己的财产检查之后

Javascript &引用;无法读取未定义的属性";即使在自己的财产检查之后,javascript,node.js,socket.io,undefined,Javascript,Node.js,Socket.io,Undefined,我一直在测试一个使用node.js和socket.io的web应用程序。一切正常,但在一次单独的测试中,我遇到了以下错误: "TypeError: Cannot read property 'socket' of undefined" 这是错误所指的行: for(var ID in playersPublic) { if(clients.hasOwnProperty(ID)) { clients[ID].socket.emit('players', pl

我一直在测试一个使用node.js和socket.io的web应用程序。一切正常,但在一次单独的测试中,我遇到了以下错误:

"TypeError: Cannot read property 'socket' of undefined"
这是错误所指的行:

for(var ID in playersPublic) {
        if(clients.hasOwnProperty(ID)) {
            clients[ID].socket.emit('players', playersPrivate[ID].playersToEmit);
            //The following line is where the error happened:
            clients[ID].socket.emit('food', playersPrivate[ID].foodToEmit);
        }
    }
绝对没有明显的理由发生这样的错误。我不能让它再次发生,也不知道是什么具体情况导致了它,但我很担心,因为使服务器崩溃——即使只有一次——意味着代码逻辑中的某些错误,一旦服务器公开,可能会导致更多错误或崩溃。此外,即使在使用hasOwnProperty显式检查是否定义了客户机[ID]之后,我仍然对如何定义客户机[ID]感到困惑——更令人困惑的是,错误引用了第二行尝试访问客户机[ID].socket,因此在上一行 在线访问它没有问题。在什么可能的情况下会发生这样的事情

编辑:我添加了以下日志:

   if(clients.hasOwnProperty(ID)) {
        if(clients[ID] == null) {
            console.log('NULL BEFORE');
        }
        clients[ID].socket.emit('players', playersPrivate[ID].playersToEmit);
        if(clients[ID] == null) {
            console.log('NULL AFTER');
        }
        clients[ID].socket.emit('food', playersPrivate[ID].foodToEmit);
    }
这导致控制台中出现以下输出:

NULL AFTER
G:\ioserver.js:262
                        clients[ID].socket.emit('food', playersPrivate[ID].foodToEmit);
                                    ^

TypeError: Cannot read property 'socket' of undefined
emitting players...3pn9-inWwAn_cQaiAAAB
disconnecting user...3pn9-inWwAn_cQaiAAAB
emitting food...3pn9-inWwAn_cQaiAAAB
G:\ioserver.js:267
                        clients[ID].socket.emit('food', playersPrivate[ID].foodToEmit);
                                    ^

TypeError: Cannot read property 'socket' of undefined

那么套接字发射怎么会导致对象变为空/未定义呢?

显然,错误是由以下事件链引起的。注意,当套接字断开连接时,它在clients对象中的对应实例将被删除。因此,这就是发生的情况(很少):

  • 用户连接,并在客户端对象中创建具有其ID的实例
  • 发射函数触发器。服务器检查客户端是否有一个具有用户ID的密钥。服务器开始第一次发射(错误前的行)
  • 用户断开连接,并删除客户端对象中ID为的实例
  • 第一次发射完成。服务器尝试开始第二次发射,但客户端[ID]不再存在
  • 通过添加三个日志(一个在用户断开连接时,一个在第一次发射前,一个在第二次发射前)证明了这一点(所有日志都带有用户ID)。以下是控制台中的结果:

    NULL AFTER
    G:\ioserver.js:262
                            clients[ID].socket.emit('food', playersPrivate[ID].foodToEmit);
                                        ^
    
    TypeError: Cannot read property 'socket' of undefined
    
    emitting players...3pn9-inWwAn_cQaiAAAB
    disconnecting user...3pn9-inWwAn_cQaiAAAB
    emitting food...3pn9-inWwAn_cQaiAAAB
    G:\ioserver.js:267
                            clients[ID].socket.emit('food', playersPrivate[ID].foodToEmit);
                                        ^
    
    TypeError: Cannot read property 'socket' of undefined
    

    因此,简单的解决方法是在第一次发射后再次检查客户机[ID]是否为空。

    因此,显然错误是由以下事件链引起的。注意,当套接字断开连接时,它在clients对象中的对应实例将被删除。因此,这就是发生的情况(很少):

  • 用户连接,并在客户端对象中创建具有其ID的实例
  • 发射函数触发器。服务器检查客户端是否有一个具有用户ID的密钥。服务器开始第一次发射(错误前的行)
  • 用户断开连接,并删除客户端对象中ID为的实例
  • 第一次发射完成。服务器尝试开始第二次发射,但客户端[ID]不再存在
  • 通过添加三个日志(一个在用户断开连接时,一个在第一次发射前,一个在第二次发射前)证明了这一点(所有日志都带有用户ID)。以下是控制台中的结果:

    NULL AFTER
    G:\ioserver.js:262
                            clients[ID].socket.emit('food', playersPrivate[ID].foodToEmit);
                                        ^
    
    TypeError: Cannot read property 'socket' of undefined
    
    emitting players...3pn9-inWwAn_cQaiAAAB
    disconnecting user...3pn9-inWwAn_cQaiAAAB
    emitting food...3pn9-inWwAn_cQaiAAAB
    G:\ioserver.js:267
                            clients[ID].socket.emit('food', playersPrivate[ID].foodToEmit);
                                        ^
    
    TypeError: Cannot read property 'socket' of undefined
    

    因此,简单的解决方法是再次检查客户端[ID]在第一次发射后是否为空。

    该属性可以存在,但其值为
    未定义
    let a={x:undefined}
    属性可以具有值
    undefined
    <代码>变量obj={foo:undefined};log(obj.hasOwnProperty(foo));obj.foo.bar第一行和第二行中的
    客户机[ID]
    是什么?您可以共享console.log吗?拥有该属性仍然意味着该值可能是未定义的,正如@u Original所指出的,问题一定出在侦听
    播放器
    消息的代码中。它正在更改
    客户端
    数组。该属性可以存在,但其值为
    未定义
    let a={x:undefined}
    属性可以具有值
    undefined
    <代码>变量obj={foo:undefined};log(obj.hasOwnProperty(foo));obj.foo.bar第一行和第二行中的
    客户机[ID]
    是什么?您可以共享console.log吗?拥有该属性仍然意味着该值可能是未定义的,正如@u Original所指出的,问题一定出在侦听
    播放器
    消息的代码中。它正在更改
    客户端
    数组。