以同步方式执行异步调用

Executing asynchronous calls in a synchronous manner

本文关键字:异步 调用 执行 方式 同步      更新时间:2023-09-26

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

我编写了一个递归函数,该函数遍历目录结构并对某些文件执行操作。此函数使用异步 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

查找步骤模块。它可以链接异步函数调用并将结果从一个传递到另一个。

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

编号 : 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
            }
        })
    });

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

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

在上行中,我们使用"A"通过函数 A 传递值返回值

并且函数 D 只有在函数 B 和函数 C 执行完成时才会执行。

如果任何函数出现错误,那么其他函数的执行将被终止,下面的函数将被执行。

function (err, results) {}

成功执行所有函数时,"结果"将包含 async.auto 中定义的所有函数的结果

function (err, results) {}

看看对原始代码的修改,它在没有异步帮助程序库的情况下做你想要的事情。

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!!!');
});

这样的事情会起作用 - 对代码的基本更改是将循环转换为递归调用,该调用使用列表直到完成。这样就可以添加外部回调(您可以在解析完成后进行一些处理)。

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');
  }
});

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

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
});

我一直在使用syncrhonize.js取得了巨大的成功。甚至还有一个挂起的拉取请求(效果很好)来支持具有多个参数的异步函数。比节点同步恕我直言更好、更容易使用。额外的好处是它具有易于理解和全面的文档,而节点同步则没有。

支持两种不同的同步连接方法,一种是延迟/等待模型(如 @Mariusz Nowak 建议的那样)和更精简但不那么精细的功能目标方法。每个文档都非常简单。

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

由 npm 安装。

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

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