2015-11-17 82 views
1

我在Node.js中運行的程序中有一個for-loop。該函數是來自xray包的x(),我正在使用它來從網頁中抓取並接收數據,然後將該數據寫入文件。這個程序用於刮〜100頁時是成功的,但我需要刮〜10000頁。當我嘗試刮取大量頁面時,會創建這些文件,但它們不包含任何數據。我相信這個問題存在,因爲for循環在繼續下一次迭代之前不等待x()返回數據。Node.js強制等待函數完成

有沒有辦法讓節點等待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'); 
                                
} 

注:有些我刮不返回任何值

+3

承諾是非常有益的在這裏。最受歡迎的圖書館之一叫做Bluebird。 –

+1

我同意Jared Dykstra。你想要1)擺脫循環體,並將其構造爲「承諾」。 2)在第一次調用之前,先設置一個計數器,例如'ct = array.length',3)不斷調用自己,直到計數器遞減爲0. – paulsm4

回答

2

您的代碼的問題在於您並未等待將文件寫入文件系統。 比逐一下載文件更好的方法是一次完成它們,然後等待它們完成,而不是一個接一個地處理它們,然後繼續下一個。

用於處理nodejs中promise的推薦庫之一是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'); 
}); 
+0

這個工程,非常感謝你!唯一不是代碼的錯誤,但是當我傳入一個非常大的數組時,它會拋出一個ECONNRESET錯誤。任何想法如何避免這種情況? –

+1

這可能表示請求處理時間過長並且請求超時。您可能需要增加請求超時。無論採用哪種方式,您都需要在服務器上捕捉異常情況以查看詳細信息。使用app.use(function(err){...});如果使用快遞。 – Don

2

你不能讓一個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(); 
+0

x()。write()返回一個writeStream,所以需要('end',function(){next()})的迭代器到下一個'end'事件發出'x(url,'css celectors')。write('filepath')。' – Sean

+0

@Sean - 我不知道那個圖書館,但是我想我找到了這個文檔,並編輯了我的答案以使用不同的形式。據推測,OP可以根據其具體需求調整這種一般形式。 – jfriend00

+0

謝謝,我是否將「結束」更改爲規範或是關鍵字? –