[英]Make forEach asynchronous in JavaScript
I'm trying to understand the asynchronous programming Node.js but stalled on this code. 我正在尝试理解异步编程Node.js但在此代码上停滞不前。
This function in their callback returns an array of files in a directory: 它们的回调中的这个函数返回一个目录中的文件数组:
function openDir(path, callback) {
path = __dirname + path;
fs.exists(path, function (exists) {
if (exists) {
fs.readdir(path, function (err, files) {
if (err) {
throw err;
}
var result = [];
files.forEach(function (filename, index) {
result[index] = filename;
});
return callback(result);
});
}
});
}
But when I use asynchronous code inside .forEach
, it returns nothing: 但是当我在
.forEach
使用异步代码时,它什么都不返回:
function openDir(path, callback) {
path = __dirname + path;
fs.exists(path, function (exists) {
if (exists) {
fs.readdir(path, function (err, files) {
if (err) {
throw err;
}
var result = [];
files.forEach(function (filename, index) {
fs.stat(path + filename, function (err, stats) {
if (err) {
throw err;
}
result[index] = filename;
});
});
return callback(result);
});
}
});
}
I understand why it happens, but don't understand how to write correct code. 我理解它为什么会发生,但不明白如何编写正确的代码。
The issue is that fs.stat
is also async, but you could probably do something like: 问题是
fs.stat
也是异步的,但你可以做类似的事情:
var result = [],
expectedLoadCount = files.length,
loadCount = 0;
files.forEach(function (filename, index) {
fs.stat(path + filename, function (err, stats) {
if (err) {
throw err;
}
result[index] = filename;
if (++loadCount === expectedLoadCount) callback(result);
});
});
The other answers may work well, but they are currently quite different semantically from the original code: they both execute stats
in parallel, rather than sequentially. 其他答案可能效果很好,但它们在语义上与原始代码完全不同:它们都是并行执行
stats
,而不是按顺序执行。 The forEach
will initiate as many asynchronous stats
operation as there are files in the list of files. forEach
将启动与文件列表中的文件一样多的异步stats
操作。 The completion order of those operations may quite well be different from the original order of the list. 这些操作的完成顺序可能与列表的原始顺序完全不同。 This may substantially affect the error handling logic.
这可能会严重影响错误处理逻辑。
The following approach implements a state machine, which is aimed to executes stats
asynchronously, yet sequentially (untested): 以下方法实现了一个状态机,旨在异步执行
stats
,但是按顺序(未经测试):
function openDir(path, callback) {
path = __dirname + path;
fs.exists(path, function (exists) {
if (!exists)
callback(null, null); // node (err, result) convention
else {
fs.readdir(path, function (err, files) {
if (err)
callback(err, null); // node (err, result) convention
else {
var results = [];
var i = 0;
nextStep(); // process the first file (the first step)
function nextStep() {
if (i >= files.length) // no more files?
callback(null, result); // node (err, result) convention
else {
fs.stat(path + files[i], function (err, stats) {
if (err)
callback(err, null); // node (err, result) convention
else {
results[i++] = stats;
// proceed to the next file
nextStep();
}
});
}
}
}
}
}
});
});
Promises may help to reduce the nesting level of the famous "Pyramid of Doom" like above. 承诺可能有助于降低上述着名的“末日金字塔”的筑巢水平。
try this: 尝试这个:
function openDir(path, callback) {
path = __dirname + path;
fs.exists(path, function (exists) {
var totalFiles = 0;;
if (exists) {
fs.readdir(path, function (err, files) {
if (err) {
throw err;
}
var result = [];
files.forEach(function (filename, index) {
fs.stat(path + filename, function (err, stats) {
if (err) {
throw err;
}
result[index] = filename;
totalFiles++;
if(totalFiles === files.length){
callback(result);
}
});
});
});
}
});
}
you can also use the Async module , to help on these kinds of situations 您也可以使用Async模块来帮助解决这些问题
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.