Node.js 强制等待函数完成
Node.js Force to Wait for Function to Finish
我在 运行 Node.js 的程序中有一个 for 循环。该函数是 xray 包中的 x() ,我正在使用它从网页上抓取和接收数据,然后将该数据写入文件。该程序用于抓取 ~100 页时是成功的,但我需要抓取 ~10000 页。当我尝试抓取大量页面时,会创建文件但它们不包含任何数据。我相信存在这个问题是因为 for 循环在继续下一次迭代之前不会等待 x() 到 return 数据。
有没有办法让节点在进入下一次迭代之前等待 x() 函数完成?
//takes in file of urls, 1 on each line, and splits them into an array.
//Then scrapes webpages and writes content to a file named for the pmid number that represents the study
//split urls into arrays
var fs = require('fs');
var array = fs.readFileSync('Desktop/formatted_urls.txt').toString().split("\n");
var Xray = require('x-ray');
var x = new Xray();
for(i in array){
//get unique number and url from the array to be put into the text file name
number = array[i].substring(35);
url = array[i];
//use .write function of x from xray to write the info to a file
x(url, 'css selectors').write('filepath' + number + '.txt');
}
注意:我抓取的一些页面没有 return 任何值
您不能让 for
循环等待异步操作完成。要解决此类问题,您必须进行手动迭代,并且需要挂钩异步操作的完成函数。以下是其工作原理的大纲:
var index = 0;
function next() {
if (index < array.length) {
x(url, ....)(function(err, data) {
++index;
next();
});
}
}
next();
或者,也许是这个;
var index = 0;
function next() {
if (index < array.length) {
var url = array[index];
var number = array[i].substring(35);
x(url, 'css selectors').write('filepath' + number + '.txt').on('end', function() {
++index;
next()
});
}
}
next();
您的代码存在的问题是您没有等待将文件写入文件系统。
比一个一个地下载文件更好的方法是一次性完成,然后等到它们完成,而不是一个一个地处理它们然后再继续下一个。
在 nodejs 中处理承诺的推荐库之一是 bluebird。
http://bluebirdjs.com/docs/getting-started.html
在更新的示例中(见下文),我们遍历所有 url 并开始下载,并跟踪承诺,然后一旦文件被写入,每个承诺都会得到解决。
最后,我们只是等待所有的承诺使用 Promise.all()
得到解决
这是更新后的代码:
var promises = [];
var getDownloadPromise = function(url, number){
return new Promise(function(resolve){
x(url, 'css selectors').write('filepath' + number + '.txt').on('finish', function(){
console.log('Completed ' + url);
resolve();
});
});
};
for(i in array){
number = array[i].substring(35);
url = array[i];
promises.push(getDownloadPromise(url, number));
}
Promise.all(promises).then(function(){
console.log('All urls have been completed');
});
我在 运行 Node.js 的程序中有一个 for 循环。该函数是 xray 包中的 x() ,我正在使用它从网页上抓取和接收数据,然后将该数据写入文件。该程序用于抓取 ~100 页时是成功的,但我需要抓取 ~10000 页。当我尝试抓取大量页面时,会创建文件但它们不包含任何数据。我相信存在这个问题是因为 for 循环在继续下一次迭代之前不会等待 x() 到 return 数据。
有没有办法让节点在进入下一次迭代之前等待 x() 函数完成?
//takes in file of urls, 1 on each line, and splits them into an array.
//Then scrapes webpages and writes content to a file named for the pmid number that represents the study
//split urls into arrays
var fs = require('fs');
var array = fs.readFileSync('Desktop/formatted_urls.txt').toString().split("\n");
var Xray = require('x-ray');
var x = new Xray();
for(i in array){
//get unique number and url from the array to be put into the text file name
number = array[i].substring(35);
url = array[i];
//use .write function of x from xray to write the info to a file
x(url, 'css selectors').write('filepath' + number + '.txt');
}
注意:我抓取的一些页面没有 return 任何值
您不能让 for
循环等待异步操作完成。要解决此类问题,您必须进行手动迭代,并且需要挂钩异步操作的完成函数。以下是其工作原理的大纲:
var index = 0;
function next() {
if (index < array.length) {
x(url, ....)(function(err, data) {
++index;
next();
});
}
}
next();
或者,也许是这个;
var index = 0;
function next() {
if (index < array.length) {
var url = array[index];
var number = array[i].substring(35);
x(url, 'css selectors').write('filepath' + number + '.txt').on('end', function() {
++index;
next()
});
}
}
next();
您的代码存在的问题是您没有等待将文件写入文件系统。 比一个一个地下载文件更好的方法是一次性完成,然后等到它们完成,而不是一个一个地处理它们然后再继续下一个。
在 nodejs 中处理承诺的推荐库之一是 bluebird。
http://bluebirdjs.com/docs/getting-started.html
在更新的示例中(见下文),我们遍历所有 url 并开始下载,并跟踪承诺,然后一旦文件被写入,每个承诺都会得到解决。 最后,我们只是等待所有的承诺使用 Promise.all()
得到解决这是更新后的代码:
var promises = [];
var getDownloadPromise = function(url, number){
return new Promise(function(resolve){
x(url, 'css selectors').write('filepath' + number + '.txt').on('finish', function(){
console.log('Completed ' + url);
resolve();
});
});
};
for(i in array){
number = array[i].substring(35);
url = array[i];
promises.push(getDownloadPromise(url, number));
}
Promise.all(promises).then(function(){
console.log('All urls have been completed');
});