以同步方式执行异步调用

时间:2011-05-10 14:08:56

标签: javascript node.js asynchronous

在过去的几个小时里,我一直试图围绕这个问题,但无法弄明白。我想我仍然需要习惯函数式编程风格;)

我编写了一个遍历目录结构并对某些文件执行操作的递归函数。此函数使用异步IO方法。现在我想在整个遍历完成时执行一些操作。

如何在执行所有parse调用但仍使用异步IO函数后确保执行此操作?

var fs = require('fs'),
    path = require('path');

function parse(dir) {
    fs.readdir(dir, function (err, files) {
        if (err) {
            console.error(err);
        } else {                
            // f = filename, p = path
            var each = function (f, p) {
                return function (err, stats) {
                    if (err) {
                        console.error(err);
                    } else {
                        if (stats.isDirectory()) {
                            parse(p);
                        } else if (stats.isFile()) {
                            // do some stuff
                        }
                    }
                };
            };

            var i;
            for (i = 0; i < files.length; i++) {
                var f = files[i];
                var p = path.join(dir, f);
                fs.stat(p, each(f, p));
            }
        }
    });
}

parse('.');

// do some stuff here when async parse completely finished

8 个答案:

答案 0 :(得分:12)

寻找Step module。它可以链接异步函数调用并将结果从一个调用传递到另一个。

答案 1 :(得分:4)

您可以使用异步模块。它的自动功能很棒。如果你有函数A()和函数B()和函数C()。函数B()和C()都依赖于函数A(),它使用函数A()的值返回。使用异步模块功能,您可以确保仅在功能A执行完成时才执行功能B和C.

参考:https://github.com/caolan/async

async.auto({
            A: functionA(){//code here },
            B: ['A',functionB(){//code here }],
            C: ['A',functionC(){//code here }],
            D: [ 'B','C',functionD(){//code here }]
        }, function (err, results) {
              //results is an array that contains the results of all the function defined and executed by async module
              // if there is an error executing any of the function defined in the async then error will be sent to err  and as soon as err will be produced execution of other function will be terminated
            }
        })
    });

在上面的例子中,一旦函数A执行完成,functionB和functionC将一起执行。因此,functionB和functionC将同时执行

functionB: ['A',functionB(){//code here }]

在上面的行中,我们使用&#39; A&#39;

通过functionA传递值 只有当functionB和functionC执行完成时才会执行

和functionD。

如果任何函数都有错误,那么其他函数的执行将被终止,并且将执行下面的函数。在那里你可以写出成功和失败的逻辑。

function (err, results) {}

成功执行所有功能&#34;结果&#34;将包含async.auto

中定义的所有函数的结果
function (err, results) {}

答案 2 :(得分:3)

看看原始代码的修改,它可以在没有异步帮助程序库的情况下执行您想要的操作。

var fs = require('fs'),
    path = require('path');

function do_stuff(name, cb)
{
    console.log(name);
    cb();
}

function parse(dir, cb) {
    fs.readdir(dir, function (err, files) {
        if (err) {
            cb(err);
        } else {             

            // cb_n creates a closure
            // which counts its invocations and calls callback on nth
            var n = files.length;
            var cb_n = function(callback)
            {
                return function() {
                    --n || callback();
                }
            }

            // inside 'each' we have exactly n cb_n(cb) calls
            // when all files and dirs on current level are proccessed, 
            // parent cb is called

            // f = filename, p = path
            var each = function (f, p) {
                return function (err, stats) {
                    if (err) {
                        cb(err);
                    } else {
                        if (stats.isDirectory()) {
                            parse(p, cb_n(cb));
                        } else if (stats.isFile()) {
                            do_stuff(p+f, cb_n(cb));
                            // if do_stuff does not have async 
                            // calls inself it might be easier 
                            // to replace line above with
                            //  do_stuff(p+f); cb_n(cb)();
                        }
                    }
                };
            };

            var i;
            for (i = 0; i < files.length; i++) {
                var f = files[i];
                var p = path.join(dir, f);
                fs.stat(p, each(f, p));
            }
        }
    });
}

parse('.', function()
{
    // do some stuff here when async parse completely finished
    console.log('done!!!');
});

答案 3 :(得分:1)

这样的东西会起作用 - 代码的基本更改是循环变成递归调用,在完成之前使用列表。这样就可以添加一个外部回调(在解析完成后你可以进行一些处理)。

var fs = require('fs'),
  path = require('path');

function parse(dir, cb) {
    fs.readdir(dir, function (err, files) {
        if (err)
          cb(err);
        else 
          handleFiles(dir, files, cb);
    });
}

function handleFiles(dir, files, cb){
  var file = files.shift();
  if (file){
    var p = path.join(dir, file);
    fs.stat(p, function(err, stats){
      if (err)
        cb(err);
      else{
        if (stats.isDirectory())
          parse(p, function(err){
            if (err)
              cb(err);
            else
              handleFiles(dir, files, cb);
          });
        else if (stats.isFile()){
          console.log(p);
          handleFiles(dir, files, cb);
        }
      }
    })
  } else {
    cb();
  }

}


parse('.', function(err){
  if (err)
    console.error(err);
  else {
    console.log('do something else');
  }
});

答案 4 :(得分:1)

请参阅以下解决方案,它使用deferred模块:

var fs   = require('fs')
  , join = require('path').join
  , promisify = require('deferred').promisify

  , readdir = promisify(fs.readdir), stat = promisify(fs.stat);

function parse (dir) {
    return readdir(dir).map(function (f) {
        return stat(join(dir, f))(function (stats) {
            if (stats.isDirectory()) {
                return parse(dir);
            } else {
                // do some stuff
            }
        });
    });
};

parse('.').done(function (result) {
    // do some stuff here when async parse completely finished
});

答案 5 :(得分:1)

我一直在使用syncrhonize.js取得巨大成功。甚至有一个挂起的拉取请求(效果很好)来支持具有多个参数的异步函数。比node-sync imho更好更容易使用。添加了奖励,它具有易于理解和完整的文档,而节点同步则没有。

支持两种不同的方法来连接同步,一个deferred / await模型(就像@Mariusz Nowak所建议的那样)和一个更细微但不那么精细的功能目标方法。每个文档都非常简单。

答案 6 :(得分:0)

建议使用node-seq https://github.com/substack/node-seq

由npm安装。

我正在使用它,我喜欢它..

答案 7 :(得分:0)

查找node-sync,这是一个简单的库,允许您以同步方式调用任何异步函数。主要的好处是它使用javascript本机设计 - Function.prototype.sync函数,而不是你需要学习的重API。另外,通过node-sync同步调用的异步函数不会阻塞整个进程 - 它只阻塞当前线程!