以同步方式执行异步调用
Executing asynchronous calls in a synchronous manner
在过去的几个小时里,我一直在试图解决这个问题,但无法弄清楚。我想我仍然需要习惯函数式编程风格;)
我编写了一个递归函数,该函数遍历目录结构并对某些文件执行操作。此函数使用异步 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。此外,通过节点同步同步调用的异步函数不会阻塞整个过程 - 它只会阻塞当前线程!
- 如何使用异步调用更改工厂的变量
- 使变量可用于不带闭包的异步调用
- 需要收集Javascript nodejs异步调用
- 如何使用jQuery等待来自回调的异步调用
- 使用模态库从嵌套的异步调用中生成javascript同步代码
- 在forEach内部进行异步调用
- jQuery没有指定异步调用级别async:false
- SPA异步调用在IE 11中不起作用
- Ember.js-模型find()方法中的异步调用
- Javascript/JQuery处理并发/异步调用和数据竞争
- 在异步调用返回之前隐藏页面
- ExtJs 处理异步调用
- ES6:在异步调用中使用生成器
- Angular js - 异步调用 $scope.users 后不更新模态值
- 在每个循环上完成异步调用,然后转到下一个节点 js
- 从异步调用返回数组,然后为数组的每个元素返回其他异步调用
- 使用 AngularJS 的异步调用
- 循环内部的Javascript异步调用
- 使用Canvas和ForEach处理异步调用
- JavaScript/promise,对sharepoint的多个异步调用