【问题标题】:Asynchronous for loop: how do I make the for loop wait for function to finish?异步 for 循环:如何让 for 循环等待函数完成?
【发布时间】:2014-08-02 01:35:37
【问题描述】:

我绞尽脑汁想弄清楚如何排序/放置回调以获得我需要的东西。

我有一个循环来检查文件是否存在。我希望它在完成后回调,但 for 循环和回调在“fs.open”完成之前完成......典型的异步问题。

我正在使用 node v0.10.29express v3.14.0,并且正在考虑使用“async”库,但同样,只是无法弄清楚我需要的逻辑......

这是我所拥有的:

输入

function checkForAllFiles(callback)
{
    var requiredFiles = [];
    requiredFiles[requiredFiles.length] = "../Client/database/one.js";
    requiredFiles[requiredFiles.length] = "../Client/database/two.dat";
    requiredFiles[requiredFiles.length] = "../Client/database/three.xml";
    requiredFiles[requiredFiles.length] = "../Client/database/four.dat";
    requiredFiles[requiredFiles.length] = "../Client/database/five.dat";
    requiredFiles[requiredFiles.length] = "../Client/database/six.xml";

    var missingFiles = [];
    for(var r=0; r<requiredFiles.length; r++)
    {
        fs.open(requiredFiles[r], 'r', function(err, fd){
            if(err)
            {
                missingFiles[missingFiles.length] = err.path;
                console.log("found missing file = ", err.path);
            }
        });
        console.log("r = ", r);
    }
    console.log("sending callback: ", missingFiles);
    callback(missingFiles);
}

输出

0
1
2
3
4
5
sending callback: []
found missing file: ../Client/database/three.xml

期望的输出

0
1
found missing file: ../Client/database/three.xml
2
3
4
5
sending callback: ["../Client/database/three.xml"]

【问题讨论】:

  • 为了好玩,您可以使用Array.push() 方法将项目添加到您的requriedFiles 数组:例如requiredFiles.push("../Client/database/one.js");
  • 会的! ;D 我试试看

标签: javascript node.js asynchronous


【解决方案1】:

我会在异步模块中使用reject 方法(我看到你已经找到了)。它将在其回调中返回一个数组,其中包含 匹配指定检查函数的任何元素。对于检查功能,我建议只使用fs.exists 而不是在fs.open 上查看错误。

使用这些功能,您实际上可以将整个检查减少到一行。像这样的:

function checkForAllFiles(callback)
{
    var requiredFiles = [];
    requiredFiles[requiredFiles.length] = "../Client/database/one.js";
    requiredFiles[requiredFiles.length] = "../Client/database/two.dat";
    requiredFiles[requiredFiles.length] = "../Client/database/three.xml";
    requiredFiles[requiredFiles.length] = "../Client/database/four.dat";
    requiredFiles[requiredFiles.length] = "../Client/database/five.dat";
    requiredFiles[requiredFiles.length] = "../Client/database/six.xml";

    async.reject(requiredFiles, fs.exists, callback);
}

callback 将使用一个仅包含不存在的文件的数组来调用。

【讨论】:

  • 你不需要所有这些数组设置行,你可以直接初始化它: var requiredFiles = [ '../Client/databse/one.js', '../Client/databse /two.dat', ...等]
  • 非常正确。我只是复制问题中的方法,试图让它更清楚应该去哪里。
【解决方案2】:

使用异步库和 eachSeries 方法。示例:

async.eachSeries(array,
     function(element, next) {
          // do something with element
          next();
     }
);

它将依次遍历数组并处理每个元素。调用 next 转到下一个元素。 Series 确保它按照数组的顺序执行,否则无法保证通过数组的顺序。如果您在其中调用了其他异步函数,只需传递下一个函数并在完成所有需要的函数后调用它,并且将处理下一个数组元素。

可能是这样的:

var missingFiles = []
async.eachSeries(requiredFiles, function(file, nextFile){
 fs.open(file, 'r', function(err, fd){
        if(err)
        {
            missingFiles[missingFiles.length] = err.path;
            console.log("found missing file = ", err.path);
        }
       nextFile();
    });
    console.log("r = ", file);
});
console.log("sending callback: ", missingFiles);
callback(missingFiles);

【讨论】:

  • 如果您不需要按顺序进行检查,您可以使用async.each,它应该运行得更快。此外,您可以使用fs.exists 而不是fs.open,如果您需要的所有文件都在同一个目录中,您可以使用一个fs.readdir 调用来获取该目录中的文件列表并与您的@987654327 进行交集@数组。
  • 这绝对值得一试,但由于某种原因,回调仍然在 fs 之后继续执行 :( 即使我使用 eachSeries(arr, iterator, callback) 语法:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-19
  • 2021-11-13
  • 2021-10-18
  • 1970-01-01
  • 1970-01-01
  • 2021-09-09
  • 1970-01-01
相关资源
最近更新 更多