Nodejs中如何知道异步foreach已经执行完毕?
Nodejs中如何知道异步foreach已经执行完毕?
如下有个遍历文件夹的函数,如何才能得知它已经遍历结束了? 谢谢!
function walk(path, floor, handleFile) {
// handleFile(path, floor);
floor++;
fs.readdir(path, function(err, files) {
if (err) {
console.log('read dir error');
} else {
files.forEach(function(item) {
var tmpPath =path + '/' + item;
fs.stat(tmpPath, function(err1, stats,people,factor) {
if (err1) {
console.log('stat error');
} else {
if (stats.isDirectory()) {
walk(tmpPath, floor, handleFile);
} else {
handleFile(tmpPath,item, floor);
}
}
})
});
}
});
}
要解决这个问题,我们需要确保在所有的异步操作完成后能够得到通知。这可以通过使用递归函数的完成条件来实现,或者通过引入一个计数器来跟踪尚未完成的异步操作。
以下是一个改进版本的walk
函数,它会在所有异步操作完成后调用一个回调函数:
const fs = require('fs');
function walk(path, floor, handleFile, callback) {
floor++;
fs.readdir(path, function(err, files) {
if (err) {
console.log('read dir error');
return callback(err);
}
let remainingFiles = files.length;
if (remainingFiles === 0) {
return callback(null); // 如果没有文件,直接回调
}
files.forEach(function(item) {
const tmpPath = path + '/' + item;
fs.stat(tmpPath, function(err1, stats) {
if (err1) {
console.log('stat error');
return callback(err1);
}
if (stats.isDirectory()) {
walk(tmpPath, floor, handleFile, function(err) {
if (err) {
return callback(err);
}
remainingFiles--;
if (remainingFiles === 0) {
callback(null);
}
});
} else {
handleFile(tmpPath, item, floor);
remainingFiles--;
if (remainingFiles === 0) {
callback(null);
}
}
});
});
});
}
// 使用示例
walk('/some/path', 0, function(path, name, level) {
console.log(`Processed file: ${path} at level ${level}`);
}, function(err) {
if (err) {
console.error('Walk completed with errors:', err);
} else {
console.log('Walk completed successfully.');
}
});
解释
- 参数调整:
walk
函数现在接受一个额外的参数callback
,用于在遍历完成后调用。 - 剩余文件计数器:引入了一个
remainingFiles
变量来跟踪尚未处理的文件数量。 - 递归调用:当遍历到子目录时,递归调用
walk
函数,并在每次递归调用完成后减少remainingFiles
的值。 - 完成检查:在所有异步操作完成后(即
remainingFiles
变为0),调用callback
函数。
这样,我们就可以在所有文件和子目录都被处理后得到通知。
用async
这个库把
用 https://github.com/alsotang/eventr 来进行消息同步
水平不够,wind的文档真难看懂。。。突袭到了半夜模仿着写了,心里没底,请指点下,谢谢: 1 这么样用异步函数+异步流程控制库,和直接用同步函数+个nexttick有什么区别? 2 有forEach、递归的方法,如何既利用异步的高效性,又能得到全部执行完毕的点?
var fs = require(‘fs’); var Wind = require(‘Wind’); var Binding = Wind.Async.Binding;
var myPath = ‘e:/nodejs/home/public’; fs.readdirAsync = Binding.fromStandard(fs.readdir); fs.statAsync = Binding.fromStandard(fs.stat);
var walk = eval(Wind.compile(“async”,function (path, floor, handleFile) { floor++;
var myReadDirResult = $await(fs.readdirAsync(path));
//不知道为什么,forEach不行
for(var i = 0 ; i < myReadDirResult.length ; i++ ){
var item = myReadDirResult[i];
var tmpPath = path + ‘/’ + item;
console.log(‘tmpPath:’ + tmpPath);
var myStatResult = $await(fs.statAsync(tmpPath));
if (myStatResult.isDirectory()){
$await(walk(tmpPath, floor, handleFile).start());
}
else{
handleFile(tmpPath);
}
}
console.log(path + ‘文件夹结束’);
}));
var main = eval(Wind.compile(“async”,function () { $await(walk(myPath, 0, function(filePath){ }).start()); console.log(‘结束’); }));
main().start();
console.log(‘这是最后一行’);
异步坑死人
弄个变量在回调函数里累加,变量的大小等于文件的个数不就知道遍历完成了么
function walk (path, handleFile, callback) {
var len = 1, // 文件|目录数,起始一个
floor = 0; // 第x个目录?
function done () {
// 完成任务, 运行回调函数
if (--len === 0) {
callback();
}
}
function composeErr (err) {
// 错误处理
console.log('stat error');
done(); // 以错误内容完成
}
function composeDir (path) {
// 目录处理
floor++;
fs.readdir(path, function (err, files) {
if (err) {
console.log('read dir error');
done(); // 目录完成
return;
}
len += files.length; // 子文件|子目录计数
files.forEach(function (filename) {
compose(path + '/' + filename); // 子内容新的操作
});
done(); // 目录完成
});
}
function composeFile (path) {
// 文件处理
handleFile(path, floor);
done(); // 文件完成
}
function compose (path) {
fs.stat(path, function (err, stats) {
if (err) {
composeErr(err);
return;
}
if (stats.isDirectory()) {
composeDir(path);
return;
}
composeFile(path);
});
}
compose(path);
}
async.map([],function(item,call) { //do…全局变量值 call(null, null) },function(err,result){ //do。。。获取变量值 })
2015-11-05 16:20:38 现在别用async了
#!/usr/bin/env node
'use strict';
const Promise = require(‘bluebird’);
const fs = Promise.promisifyAll(require(‘fs’));
const co = require(‘co’);
// example
const handleFile = f => f;
const walkAsync = co.wrap(function* (path) {
var files = yield fs.readdirAsync(path);
var ret = [];
for(let f of files) {
let p = path + ‘/’ + f;
var s = yield fs.statAsync§;
if (s.isDirectory()) {
var r = yield walkAsync§;
ret = ret.concat®;
} else {
ret.push§
handleFile§;
}
}
return ret;
});
co(function *(){
var files = yield walkAsync(__dirname);
console.log(files);
}).catch(e => console.error(e.stack || e));
不小心用了var…
我想说,foreach不是同步的吗
为了确定异步 forEach
遍历已经完成,可以使用一个计数器来跟踪正在执行的异步操作的数量。当所有操作都完成后,这个计数器将变为零,从而可以执行回调函数。
以下是修改后的示例代码:
const fs = require('fs');
function walk(path, floor, handleFile, callback) {
floor++;
let remaining = 0;
fs.readdir(path, function(err, files) {
if (err) {
console.log('read dir error');
return callback(err);
}
files.forEach(function(item) {
remaining++;
var tmpPath = path + '/' + item;
fs.stat(tmpPath, function(err1, stats) {
if (err1) {
console.log('stat error');
} else {
if (stats.isDirectory()) {
walk(tmpPath, floor, handleFile);
} else {
handleFile(tmpPath, item, floor);
}
}
checkCompletion();
});
function checkCompletion() {
if (--remaining === 0) {
callback(); // 所有操作完成时调用回调
}
}
});
checkCompletion();
});
}
// 使用示例
walk('/some/path', 0, (filePath, name, depth) => {
console.log(`File: ${filePath} at depth ${depth}`);
}, () => {
console.log('Directory traversal completed.');
});
解释:
- 计数器:在
walk
函数内部定义了一个名为remaining
的变量,用于跟踪当前正在进行的异步操作数量。 - 递增计数器:每次处理一个文件或目录时,增加
remaining
计数器。 - 递减计数器:在每个异步操作完成之后,减少
remaining
计数器。 - 检查完成:通过
checkCompletion
函数检查是否所有操作已完成。如果remaining
变为零,则调用回调函数callback()
表示所有操作已结束。
这样,我们就能确定所有异步操作都已经完成了。