Javascript – .map耗尽内存

我的图书馆:

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

我有很多我想分析的XML文件。 我能够使用这个函数创build一个到所有文件的path数组:

 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); }); } 

现在我想通过每一个文件去parsing它。

我有2个function来做到这一点:

 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函数输出一个包含超过20kstring的文件path的数组)函数:

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

我得到一个JavaScript堆内存不足的错误:

致命错误:CALL_AND_RETRY_LAST分配失败 – JavaScript堆内存不足

但是,当我通过传递实际文件的path一次运行函数:

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

我得到所需的输出。

我究竟做错了什么?

迭代nK文件发生asynchronous。

1)你正在获取文件列表

2)通过.map调用openFileparseFile ,它们是asynchronous函数,读取和parsing需要时间。

所以由于asynchronous进入下一个文件而没有完成前一个调用垃圾收集器扫描内存,这里是内存不足的问题。

考虑一下读取20K大小不同的文件。

所以这里是解决scheme:

使用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(); }); }); 

PS随时评论和解决我的答案中的代码问题。

这是您的工作负载更多资源需求的简单情况。 我会考虑增加堆大小以满足您的需求,而不是更改源代码。

我build议--max_old_space_size进行相应设置以满足要求 – 但这可能是一个反复的过程。

希望这可以帮助。