Nodejs串联运行函数

时间:2014-04-07 08:11:23

标签: javascript node.js asynchronous callback synchronous

所以现在我尝试使用Nodej来访问文件,以便将它们写入服务器并进行处理。

我已将其拆分为以下步骤:

  • 遍历目录以生成所有文件路径的数组
  • 将来自每个文件路径的原始文本数据放入另一个数组
  • 处理原始数据

前两个步骤正常,使用这些功能:

var walk = function(dir, done) {
    var results = [];
    fs.readdir(dir, function(err, list) {
        if (err) return done(err);
        var pending = list.length;
        if (!pending) return done(null, results);
        list.forEach(function(file) {
            file = path.resolve(dir, file);
            fs.stat(file, function(err, stat) {
                if (stat && stat.isDirectory()) {
                    walk(file, function(err, res) {
                        results = results.concat(res);
                        if (!--pending) done(null, results);
                    });
                } else {
                    results.push(file);
                    if (!--pending) done(null, results);
                }
            });
        });
    });
};
function processfilepaths(callback) {
    // reading each file
    for (var k in filepaths) { if (arrayHasOwnIndex(filepaths, k)) {
        fs.readFile(filepaths[k], function (err, data) {
            if (err) throw err;
            rawdata[k] = data.toString().split(/ *[\t\r\n\v\f]+/g);
            for (var j in rawdata[k]) { if (arrayHasOwnIndex(rawdata[k], j)) {
                rawdata[k][j] = rawdata[k][j].split(/: *|: +/);
            }}
        });
    }}
    if (callback) callback();
}

显然,我想在加载完所有数据后调用函数processrawdata()。但是,使用回调似乎不起作用。

walk(rootdirectory, function(err, results) {
    if (err) throw err;
    filepaths = results.slice();
    processfilepaths(processrawdata);
});

这绝不会导致错误。除了processrawdata()总是在processfilepaths()之前完成之外,一切似乎都运行得很好。我做错了什么?

3 个答案:

答案 0 :(得分:1)

我认为对于您的问题,您可以将async模块用于Node.js:

async.series([
    function(){ ... },
    function(){ ... }
]);

<小时/> 为了回答你的实际问题,我需要解释Node.js的工作原理:
比如说,当你调用异步操作(比如mysql db query)时,Node.js会向MySQL发送“执行此查询”。由于此查询将花费一些时间(可能是几毫秒),Node.js使用MySQL异步库执行查询 - 返回事件循环并在等待MySQL返回给我们时执行其他操作。就像处理那个HTTP请求一样。         因此,在您的情况下,两个函数都是独立的,几乎并行执行。

了解更多信息:

答案 1 :(得分:1)

您遇到回调调用和异步调用函数的问题。 IMO我建议您在执行所有函数后使用after-all等库来执行回调。

以下是一个例子,一旦调用了包含done的所有函数,就会调用函数next

var afterAll = require('after-all');

// Call `done` once all the functions
// wrapped with next() get called
next = afterAll(done);

// first execute this
setTimeout(next(function() {
  console.log('Step two.');
}), 500);

// then this
setTimeout(next(function() {
  console.log('Step one.');
}), 100);

function done() {
  console.log("Yay we're done!");
}

答案 2 :(得分:0)

function processfilepaths(callback) {
    // reading each file
    for (var k in filepaths) { if (arrayHasOwnIndex(filepaths, k)) {
        fs.readFile(filepaths[k], function (err, data) {
            if (err) throw err;
            rawdata[k] = data.toString().split(/ *[\t\r\n\v\f]+/g);
            for (var j in rawdata[k]) { if (arrayHasOwnIndex(rawdata[k], j)) {
                rawdata[k][j] = rawdata[k][j].split(/: *|: +/);
            }}
        });
    }}
    if (callback) callback();
}

意识到你有:

for
    readfile (err, callback) {... }
if ...

Node将异步调用每个readfile,它只设置事件和回调,然后当它完成调用每个readfile时,它将执行if,之后回调可能甚至有机会被调用。

您需要使用Promises或像async这样的承诺模块来序列化它。你会做什么看起来像:

async.XXXX(filepaths, processRawData, 
   function (err, ...) {
      // function for when all are done
      if (callback) callback();
   }
);

其中XXXX是库中的函数之一,如series, parallel, each等...您还需要知道的唯一事情就是在您的进程中原始数据,async会给您一个回调函数完成后。除非你真的需要顺序访问(我不认为你这样做),否则使用parallel可以排队尽可能多的i / o事件,它应该执行得更快,可能只是稍微一点,但它会更好利用硬件。