Javascript 以同步方式执行异步调用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5951350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 19:39:13  来源:igfitidea点击:

Executing asynchronous calls in a synchronous manner

javascriptnode.jsasynchronous

提问by Sven Jacobs

I've been trying to wrap my head around this issue for the last hours but can't figure it out. I guess I still have to get used to the functional programming style ;)

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

I wrote a recursive function that traverses through a directory structure and does things to certain files. This functions uses the asynchronous IO methods. Now I want to perform some action when this whole traversing is done.

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

How would I make sure that this action is performed after all parsecalls have been performed but still use the asynchronous IO functions?

我如何确保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

采纳答案by Phillip Kovalev

Look for Step module. It can chain asynchronous functions calls and pass results from one to another.

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

回答by Abhimanyu

You could use async module . Its auto function is awesome . If you have function A() and function B() and function C() . Both function B() and C() depend of function A() that is using value return from function A() . using async module function you could make sure that function B and C will execute only when function A execution is completed .

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

Ref : https://github.com/caolan/async

参考: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
            }
        })
    });

In above example functionB and functionC will execute together once function A execution will be completed . Thus functionB and functionC will be executed simultaneously

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

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

In above line we are passing value return by functionA using 'A'

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

and functionD will be executed only when functionB and functionC execution will be completed .

而functionD只有在functionB和functionC执行完成后才会被执行。

if there will be error in any function , then execution of other function will be terminated and below function will be executed .where you could write your logic of success and failure .

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

function (err, results) {}

On succesfull execution of all function "results" will contain the result of all the functions defined in async.auto

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

function (err, results) {}

回答by Andrey Sidorov

Take a look at modification of your original code which does what you want without async helper libs.

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

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

回答by Mariusz Nowak

See following solution, it uses deferredmodule:

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

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

回答by shellscape

I've been using syncrhonize.jswith great success. There's even a pending pull request (which works quite well) to support async functions which have multiple parameters. Far better and easier to use than node-sync imho. Added bonus that it has easy-to-understand and thorough documentation, whereas node-sync does not.

我一直在使用syncrhonize.js并取得了巨大的成功。甚至还有一个挂起的拉取请求(效果很好)来支持具有多个参数的异步函数。imho 比 node-sync 更好也更容易使用。额外的好处是它具有易于理解和详尽的文档,而 node-sync 则没有。

Supports two different methods for wiring up the sync, a defered/await model (like what @Mariusz Nowak was suggesting) and a slimmer though not-as-granular function-target approach. The docs are pretty straightforward for each.

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

回答by Geoff Chappell

Something like this would work -- basic change to your code is the loop turned into a recursive call that consumes a list until it is done. That makes it possible to add an outer callback (where you can do some processing after the parsing is 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');
  }
});

回答by murvinlai

Recommend to use node-seq https://github.com/substack/node-seq

推荐使用 node-seq https://github.com/substack/node-seq

installed by npm.

由 npm 安装。

I'm using it, and I love it..

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

回答by Francesco Casula

Look for node-sync, a simple library that allows you to call any asynchronous function in synchronous way. The main benefit is that it uses javascript-native design - Function.prototype.sync function, instead of heavy APIs which you'll need to learn. Also, asynchronous function which was called synchronously through node-sync doesn't blocks the whole process - it blocks only current thread!

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