Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/471.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 全局对象的迭代键试图访问非同步回调中未定义的变量_Javascript_Arrays_Node.js - Fatal编程技术网

Javascript 全局对象的迭代键试图访问非同步回调中未定义的变量

Javascript 全局对象的迭代键试图访问非同步回调中未定义的变量,javascript,arrays,node.js,Javascript,Arrays,Node.js,globalObject示例(根据连接的用户和每个用户项不断变化): 有时我会遇到致命错误,崩溃: globalObject = { "1001":[{id:1},{id:2}], "1002":[{id:2},{id:3}]} 在这一行: TypeError: Cannot read property 'length' of undefined 尽管在任何时候从程序的不同部分推送不同的用户,但我删除globalObject[key]的唯一地方是在处理完用户之后 那么,当我通过迭代器(for

globalObject示例(根据连接的用户和每个用户项不断变化):

有时我会遇到致命错误,崩溃:

globalObject = { "1001":[{id:1},{id:2}], "1002":[{id:2},{id:3}]}
在这一行:

TypeError: Cannot read property 'length' of undefined
尽管在任何时候从程序的不同部分推送不同的用户,但我删除globalObject[key]的唯一地方是在处理完用户之后

那么,当我通过迭代器(forEach)访问一个键时,为什么它不能存在(未定义),而迭代器(forEach)确保该键存在,并且直到最后才会删除它呢

编辑:


我认为原因是我在setInterval(每200ms)内调用forEach,因此在forEach完成之前,它会再次被调用,因此会删除密钥。如何使其更加同步,以避免在很短的时间间隔内对相同的键调用两次?

最可能的情况是,您一次运行的循环不止一个,这会造成潜在的竞争条件(因为异步数据库调用)其中一个循环删除另一个循环仍在处理的键

最好的解决办法是避免同时运行其中两个,并防止可能的比赛条件。如果您向我们展示调用代码上下文,这样我们就可以看到如何/如果它可以在另一个完成之前被多次调用,那么我们可以建议一种避免这种情况的方法

即使没有这一点,您也可以像这样保护您免受竞争条件的影响:

console.log('User has  ' + globalObject[key].length + ' items)
额外的
!globalObject[key]
添加到
if
语句中的复选框可防止其他人在数据库调用过程中删除密钥


顺便说一句,如果,则不需要此

  Object.keys(globalObject).forEach(function(key) {
    database.query('SELECT * from accounts WHERE `ID` = ' + key + ' LIMIT 1', function(error, rows, fields) {
      // if the db says no rows or the key is already gone, then nothing to do
      if (rows.length == 0 || !globalObject[key]) return;
      console.log('User has  ' + globalObject[key].length + ' items')
      globalObject[key].forEach(function(item) {
        console.log('Item ID is ' + item.id)
      });
      delete globalObject[key];
    });
  });
因为
Object.keys(globalObject.forEach()
在数组为空时可以正常工作(只是与此无关)


根据您的评论进行更多解释:

.forEach()
循环运行到结束,不会中断。但是循环中的数据库操作是非阻塞的。它们开始了,但循环不会等待它们完成。因此,将完成
.forEach()
循环,但尚未调用循环中的回调

因此,如果您有10个键,那么将启动10个数据库操作(没有一个操作已经完成)。现在,
.forEach()
循环完成。如果您的
setInterval()
在所有10个数据库操作完成之前再次调用此代码,则新的
.forEach()
循环将运行并根据第一个循环(当其数据库操作最终完成时)即将删除的键启动更多的数据库操作。现在,在第二个
.forEach()
循环运行之后,从第一个循环开始的数据库操作将完成并删除键。然后,在它们完成后,第二个
.forEach()
循环中的数据库操作将完成并调用它们的回调,它们将尝试使用现在已被第一个循环中的回调删除的键

循环本身不会同时运行。但是,在每次循环运行之后,它会设置在将来某个不确定时间运行的数据库回调,并且这些回调(如您所编码的)假定某组键没有被删除。但是,如果在开始第二个循环之前没有等到第一个循环中的所有数据库回调都完成,那么这个假设就不成立了,因为第二个循环将使用第一个循环的数据库调用最终完成时将要删除的键。这将打乱第二个循环启动的数据库回调


.forEach()
调用与事件无关。它们只是Javascript中的循环,并且同步运行。数据库调用只是启动异步操作。他们的回调将在将来某个时候由事件触发。由于这些数据库调用是非阻塞异步的,
.forEach()
循环将完成,然后JS解释器将在稍后获取触发数据库回调的事件。

如果对象没有键(空对象),这显然会给你一个错误。除了你眼前的问题之外,还有一个小小的改进:从
let keys=Object.keys(globalObject)开始;如果(keys.length>0){keys.forEach(…)…
。虽然这里的每个人都在白费力气,但我投票将其作为主题关闭,因为我不是一个。您有一个带有全局变量的程序,您承认该程序在该函数运行到每个
数据库.query()之间正在更新
回电话。如果没有进一步的信息,我们无法确切地告诉您问题的真正原因,我们只能猜测。请您提出问题,以尽可能少的代码重复此问题。您是否回复电子邮件或其他内容?我在发布后立即删除了该评论,因为我注意到t太晚了。您可能想在代码中插入一个简单的控制台日志,以确保了解发生了什么。除了将
键捕获为自己的列表外,还可以设置
keys.forEach(key=>{let data=globalObject[key];console.log(
处理键${key}和相关数据${JSON.stringify(data)}
)
这样,您就可以看到您的代码将要尝试使用的内容,然后在数据库回调中有一个类似的日志,以查看是否存在数据不匹配。这是一个很好的“全局对象”赌注不应该是全局的,因为在您的查询运行时,其他代码可能会弄乱它。谢谢。我记得您来自。嘿嘿。事件一次运行一个。foreach循环不应该是一个事件吗?现在我是,两个foreach循环相互弄乱了。我找到了另一种方法来完成我想做的事情,这次没有n间隔,但我仍然有一种感觉
  Object.keys(globalObject).forEach(function(key) {
    database.query('SELECT * from accounts WHERE `ID` = ' + key + ' LIMIT 1', function(error, rows, fields) {
      // if the db says no rows or the key is already gone, then nothing to do
      if (rows.length == 0 || !globalObject[key]) return;
      console.log('User has  ' + globalObject[key].length + ' items')
      globalObject[key].forEach(function(item) {
        console.log('Item ID is ' + item.id)
      });
      delete globalObject[key];
    });
  });
if (Object.keys(globalObject).length != 0) {