【问题标题】:Nodejs Running Functions in SeriesNodejs 串联运行函数
【发布时间】:2015-01-16 21:22:54
【问题描述】:

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

我把它分成以下几个步骤:

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

前两个步骤运行良好,使用这些函数:

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() 之前完成之外,一切似乎都运行得很完美。我做错了什么?

【问题讨论】:

  • 现在你必须考虑使用 Promise 来获得更好的控制流。

标签: javascript node.js asynchronous callback synchronous


【解决方案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!");
}

【讨论】:

  • 是的,这正是我需要的!谢谢!
  • @CosmoVibe 如果此答案适合您的需求,您能否将其标记为正确答案?
  • 啊,谢谢你告诉我。没有意识到我必须标记它哈哈
【解决方案2】:

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

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


为了回答您的实际问题,我需要解释 Node.js 的工作原理:
例如,当您调用异步操作(例如 mysql db 查询)时,Node.js 将“执行此查询”发送到 MySQL。由于这个查询需要一些时间(可能是几毫秒),Node.js 使用 MySQL 异步库执行查询 - 回到事件循环并在那里做其他事情,同时等待 MySQL 回复我们。就像处理那个 HTTP 请求一样。 因此,在您的情况下,这两个功能都是独立的并且几乎并行执行。

更多信息:

【讨论】:

  • 异步对我不起作用,由于某种原因它没有改变执行顺序。我假设是因为逻辑和回调函数一样,所以它的作用是一样的。
【解决方案3】:
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 这样的 Promise 模块来序列化它。然后你会做什么看起来像:

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

其中XXXX 是库中的函数之一,如series, parallel, each 等...您还需要知道的唯一一件事是在您的流程原始数据中,async 会在完成时为您提供回调。除非您真的需要顺序访问(我认为您不需要),否则使用并行以便您可以将尽可能多的 i/o 事件排队,它应该执行得更快,也许只是略微,但它会更好地利用硬件。

【讨论】:

    猜你喜欢
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多