Node JS不等待嵌套的内部函数调用执行



诚然,我是节点的新手,但似乎这应该可以正常工作。我正在使用多方来解析一个返回数组的表单。然后,我使用 for each 来逐步执行数组。但是 - for each 不会等待内部代码执行。不过,我有点困惑为什么不是。

var return_GROBID =  function(req, res, next) {
var form = new multiparty.Form();
var response_array = [];
form.parse(req, function(err, fields, files) {
files.PDFs.forEach(function (element, index, array) {
fs.readFile(element.path, function (err, data) {
var newPath = __dirname + "/../public/PDFs/" + element.originalFilename;
fs.writeFile(newPath, data, function (err) {
if(err) {
res.send(err);
}
GROBIDrequest.GROBID2js(newPath, function(response) {
response_array.push(response);
if (response_array.length == array.length) {
res.locals.body = response_array;
next();
}
});
});
});
});
});
}

如果有人能给我一些关于正确方法的见解,那就太好了。

编辑:谜团仍在继续。我在另一台机器上运行了这段代码,它工作了。这是怎么回事?为什么一台机器与另一台机器不一致?

我猜PDFs.forEach你只是调用内置的forEach函数,对吗?

在Javascript中,许多事情都是异步的 - 这意味着给定:

linea();
lineb();

lineb 可以在linea完成它启动的任何操作之前执行(例如,因为在异步编程中,我们不会等到网络请求返回)。

这与其他编程语言不同:大多数语言会"阻塞"直到linea完成,即使linea可能需要时间(如发出网络请求)。(这称为同步编程)。

完成序言后,回到你最初的问题:

所以forEach是一个同步函数。如果您像下面这样重写代码,它将起作用(但没有用):

PDFs.forEach(function (element, index, array) {
console.log(element.path)
}

(console.log 是 Javascript 中很少见的同步方法)。

但是在你的forEach 循环中,你有fs.readFile.注意到最后一个参数,一个函数吗?Node 将在操作完成后回调该函数(回调)。

正如观察到的那样,您的代码当前将点击 fs.readFile,说"好的,下一件事",然后继续循环中的下一项。

解决此问题的一种方法是使用异步库,只需最少更改代码。

async.forEachOf(PDFs, function(value, key, everythingAllDoneCallback) {
GROBIDrequest.GROBID2js(newPath, function(response) {
response_array.push(response);
if (response_array.length = array.length) {
...
}
everythingAllDoneCallback(null)

} );

使用此代码,您将完成所有异步工作,然后在可以安全地移动到列表中的下一项时触发回调。

像这样的节点和回调是一种非常常见的 Node 模式,Node 上的初学者材料应该很好地涵盖了它。但它是最...节点开发中意想不到的概念。

我找到的一个资源是(一个来自一组课程)关于初学者的 NodeJS:回调。这一点,以及使用阻塞(同步)和非阻塞(异步)函数,并希望这个 SO 答案,可能会提供一些启发:)

最新更新