2016-11-21 52 views
2

我的圖書館:使用Javascript - .MAP運行內存

const Promise = require('bluebird'); 
const fs = Promise.promisifyAll(require('graceful-fs')); 
const path = require('path'); 
const xml2js = Promise.promisifyAll(require('xml2js')); 

我有大量的我想要解析XML文件。我能夠創造的路徑的數組來使用此功能的所有文件:

function getFileNames(rootPath) { 
    // Read content of path 
    return fs.readdirAsync(rootPath) 
    // Return all directories 
    .then(function(content) { 
     return content.filter(function(file) { 
     return fs.statSync(path.join(rootPath, file)).isDirectory(); 
     }); 
    }) 
    // For every directory 
    .map(function(directory) { 
     // Save current path 
     let currentPath = path.join(rootPath, directory); 
     // Read files in the directory 
     return fs.readdirAsync(currentPath) 
     // Filter out the XMLs 
     .filter(function(file) { 
      return path.extname(file) === '.XML'; 
     }) 
     // Return path to file 
     .map(function(file) { 
      return path.join(rootPath, directory, file); 
     }); 
    }) 
    // Flatten array of results 
    .reduce(function(a, b) { 
     return a.concat(b); 
    }); 
} 

,現在我想走線槽的每一個文件,並解析它。

我有2個功能可以這樣做:

function openFile(filePath) { 
return fs.readFileAsync('./' + filePath) 
    .then(function(fileData) { 
    return fileData; 
    }); 
} 

function parseFile(data) { 
    return xml2js.parseStringAsync(data) 
     .then(function(xmlObject) { 
     return xmlObject; 
     }); 
} 

現在,當我把這種與.MAP(該GetFileNames函數輸出的陣列超過20K串與文件路徑)函數:

getFileNames('./XML') 
    .map(function(file) { 
    openFile(file) 
     .then(function(data) { 
     parseFile(data) 
      .then(function(object) { 
       console.log(object); 
      }); 
     }); 
    }); 

我得到一個javascript堆內存不足的錯誤:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory

但是當我運行該功能由路徑傳遞到實際的文件中的單個時間:

openFile('./XML/2016-10-1/EUROTIPOLD2016-10-1T00-00-22.5756240530.XML') 
    .then(function(data) { 
    parseFile(data) 
     .then(function(object) { 
      console.log(object); 
     }); 
    }); 

我得到所需的輸出。

我在做什麼錯?

+0

所以你說,當你以某種方式使用varaible,而不是它的工作原理硬編碼字符串的??? – epascarello

+0

對不起,編輯了這個問題。我說當我運行函數一次沒有.map函數時它的工作原理(通過傳遞一個字符串與文件的路徑)。當我在.map函數中運行它時,內存不足。 –

+1

您嘗試打開多少個文件?不要忘記異步函數,Node.js嘗試同時打開所有文件,而不是一個接一個地打開。 – Fefux

回答

1

迭代nK文件發生異步的。

1)你得到這樣做的文件

2)名單.map你打電話openFileparseFile是異步函數,它需要時間來閱讀和分析。


是因爲asynchronousity的前進到下一個文件,而無需等待完成前一個調用垃圾回收器來掃描存儲器,這裏是內存不足的問題。

想想一次讀取不同大小的20K文件。


所以這裏是解決方案:

使用async同步(eachSeries)或控制(eachLimit)迭代。

const async = require('async'); // install: npm i --save async 

let files = getFileNames('./XML'); 

// eachLimit(files, 3, 
async.eachSeries(files, 
    (file, next) => { 
    openFile(file) 
    .then(
     parseFile, 
     (err) => { 
     console.error('Cannot open file:', file, err); 
     next(); 
     }) 
    .then(
     object => { // successfully parsed file, so log it out and proceed to next file 
     console.log(object); 
     next(); 
     }, 
     (err) => { 
     console.error('Cannot parse data from file:', file, err); 
     next(); 
     }); 
}); 

p.s.隨時在我的答案中發表評論並解決代碼問題。

+1

未使用你的代碼直接,但開始使用async.eachSeries,它解決了我的問題。謝謝 –

+0

@MihaŠušteršič實際上這是一個例子(:你可以自由定義你的代碼,因爲你願意 – num8er

0

這是爲您的工作負載的更多資源需求的簡單情況。我會考慮增加堆大小以滿足您的需求,而不是更改源代碼。

我建議--max_old_space_size要建立相應的滿足需求 - 這可能是一個反覆的過程,但。

希望這會有所幫助。

+0

我認爲只有在沒有其他問題或情況下才可以解決此問題最好先調試問題,並儘可能修復或優化,只有在嚴格需要的情況下,才能繼續根據服務器的負載級別爲節點進程提供更多資源。 –