诚然,我是node的新手,但它看起来应该工作得很好。我使用多方来解析一个表单,它返回一个数组。然后,我使用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();
}
});
});
});
});
});
}如果有人能给我一些正确的方法来做这件事,那就太好了。
编辑:谜团仍在继续。我在另一台机器上运行了这段代码,它工作了。怎么一回事?为什么一台机器和另一台机器不一致?
发布于 2018-01-08 03:16:44
我猜PDFs.forEach是你在叫the built-in forEach function,对吗?
在Javascript中,许多事情都是异步的-这意味着给定:
linea();
lineb();lineb可能会在linea完成它启动的任何操作之前执行(因为在异步编程中,我们不会一直等到网络请求返回)。
这与其他编程语言不同:即使linea可能需要一些时间(比如发出网络请求),大多数语言也会“阻塞”,直到linea完成。(这称为同步编程)。
完成前言后,回到您最初的问题:
所以forEach是一个同步函数。如果你像下面这样重写你的代码,它将会工作(但没有用):
PDFs.forEach(function (element, index, array) {
console.log(element.path)
}(console.log是Javascript中一种罕见的同步方法)。
但是在你的 forEach循环中,你有fs.readFile。注意到最后一个参数了吗,一个函数?当操作完成时,节点将回调该函数(回调)。
正如观察到的,您的代码当前将命中该fs.readFile,说“好的,下一件事”,然后继续循环中的下一项。
解决这个问题的一种方法是使用async库,而对代码的更改最少。
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的初学者材料中有很好的介绍。但它是最.Node开发中的意外概念。
我在这上面找到的一个资源是(从一组课程中的一个)关于NodeJS For Beginners: Callbacks。这一点,再加上阻塞(同步)和非阻塞(异步)函数,希望这个答案能提供一些启示:)
https://stackoverflow.com/questions/48140506
复制相似问题