array.length 为零,但数组中有元素

IT技术 javascript arrays scope electron
2021-01-16 21:38:09

我目前正在练习使用电子,但我对 javascript 很陌生,我遇到了一个让我完全困惑的问题。我有以下代码:

    function getPaths() {
      var dirPath = document.getElementById("mdir").innerHTML;
      var filePaths = [];
      fs.readdir(dirPath, function(err, dir) {
        for(var i = 0, l = dir.length; i < l; i++) {
          var filePath = dir[i];
          filePaths.push(dirPath + "/" + filePath);
        }
      });
      console.log(filePaths);
      console.log(filePaths.length);
    }

它应该查看由 定义的目录dirPath,然后循环遍历并获取该目录中所有文件的完整路径。它将它们附加到一个数组,然后在底部,将数组记录到控制台,然后是数组的长度。令我困惑的是,给定该代码,数组像预期的那样记录到控制台,但随后控制台将长度记录为零。我目前的想法是它与作用域有关,但这没有意义,因为我在filePaths正在运行的函数上方的函数中声明了数组除非我错过了什么。谁能指出我做错了什么?

2个回答

readdir是异步的。它不会立即得到结果。您应该使用filePaths回调内部。控制台显示该值的唯一原因是因为控制台会在您展开数组时对其进行评估。

当你按下左边的小箭头时,把鼠标放在i右边盒子上。发生的情况是控制台保留对数组的引用,因此当用户展开数组时,它会显示数组的当前值。但是当你记录filePaths.length数组是空的,因为还readdir没有完成阅读,这就是你得到 0 的原因。但是当你打开控制台并按下那个箭头时,readdir已经完成了阅读,控制台将打印当前的值数组(填充后)。

在此处输入图片说明

演示问题的示例:(不是解决方案,只是为了了解真正发生的事情)

打开浏览器控制台并尝试以下代码,看看会发生什么:

var arr = [];

setTimeout(function() {
  arr.push(1, 2, 3);
}, 5000);

console.log(arr.length);

console.log(arr);

这里数组及其长度都在数组填充之前记录。数组将在 5 秒后填充。所以输出将是0和数组的字符串表示array[]现在因为数组可能有大量数据,所以在用户展开数组之前,控制台不会显示这些数据。所以控制台所做的是保持对数组的引用,直到用户按下展开箭头。如果在 5 秒之前展开数组,您将看到数组为空(尚未填充)。如果您等到 5 秒过去然后展开它,那么您会看到它已被填满,即使它被记录为一个空数组。

注意:此外,记录到控制台的行(类似于> Array(0))只是日志发生时对象/数组的字符串表示。如果对象/数组发生变化,它就不会更新。所以这有时看起来也很混乱

我希望现在清楚了。

我不建议使用setTimeout函数,因为响应时间可能因目录内容而异
2021-03-23 21:38:09
好吧,有道理!我有 Python 背景,所以这种类型的东西对我来说很陌生。还有一个问题:出于好奇,为什么readdirSync不推荐?
2021-03-26 21:38:09
好的,所以如果我做对了,我没有得到值的原因是因为 readdir 是异步的。因此,console.log() 在数组构建之前完成,结果它返回 0?
2021-04-05 21:38:09
@MaxZoom 我没有建议setTimeout作为解决方案!我刚刚用一个易于理解的例子解释了OP的问题,setTimeout用于强调问题的异步性!
2021-04-09 21:38:09
@Taira 正是!readdir只会在读取完成时注册要调用的回调,然后继续执行下一条语句并执行它(与 发生的情况几乎相同setTimeout))!如果你想使用同步版本readdirSync(但我不推荐它)。
2021-04-12 21:38:09

只是为了扩展@ibrahim-mahrir 的回答,他们的意思是这样的

function getPaths() {
    var dirPath = document.getElementById("mdir").innerHTML;
    var filePaths = [];
    fs.readdir(dirPath, function(err, dir) {
        for (var i = 0, l = dir.length; i < l; i++) {
            var filePath = dir[i];
            filePaths.push(dirPath + "/" + filePath);
        }
        console.log(filePaths);
        console.log(filePaths.length);
    });
}