nodejs分割js大文件

他们做音频处理时候遇到一个js文件ffmpeg-asm.js——17.6M。想尝试压缩下,看看能压缩多少。

由于之前一直使用fis进行前端开发,于是把ffmpeg-asm.js拿到fis工程项目中,进行压缩。

悲剧的是,报错——文件太大,爆内存了:

FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory

那行吧,我直接使用ugligy-js进行压缩。于是npm install ugligy-js安装,再进行压缩,同样依然爆内存。

这个时候打开源文件,发现文件中绝大部分都是用于内存初始化的二进制数据(%……@¥#%¥%¥),js部分并不是很多,而二进制部分没有办法压缩。然后就用了一个最笨的方法手动把二进制部分拿出来,剩下的只有100多K,然后使用fis压缩,发现100多K的js压缩后有40多K 。

然并卵。还是不能直接压缩原始文件。这么大压缩不掉,那就把文件变小去压缩,到这儿就跑到本文的主题:分割js文件。思路就是读取源文件,设定一个界限值,每个界限值大小的内容都平均分到其他文件中去。

使用nodejs分割文件,那就是用fs模块对文件进行处理。

首先不能使用readFile,因为这样也是把文件内容全部读到内存中再进行算进行计算的,同样会爆内存。

只能使用createReadStream, createWriteSteam对文件进行边读、边计算,边写文件。就是stream的操作。问题是并不能仅仅如读一个文件一样边读边操作(会造成写入失败,虽然文件数目是对的),这个需要对stream进行精确控制。于是用到了through模块的帮助。这样便可以分割文件了:

var fs = require('fs');
var readstream = fs.createReadStream('source.js');
var through = require('through');

var size = 0;
var dest = null;
var file = 0;

readstream.setEncoding('utf-8');

readstream.on('data', function (chunk) {
    size += chunk.length / 1000;
    if (size > 500) { //每个文件左右
        dest.pause();
        dest = null;
        size = 0;
        file ++;
    }
    if (!dest) {
        dest = through();
        dest.pipe(fs.createWriteStream('aim/aim' + file +'.js'));
    }
    dest.queue(chunk);
}).on('end', function () {
    // dest.emit('end');
})

需要注意的是,最后监听到end时,不能理解结束stream(不理解,如果非要有的话,就是结束时候stream中仍有数据没有完全写入,此时结束的话不能写入了).

好。分割文件结束,那就分别去压缩吧。可是到这个时候才发现——ugligy-js不能压缩有语法错误的js文件。而分割文件的时候却没有办法做到刚刚截取到语句的正常结束。

那行,就按照这个思路在读取流的时候,拿到流数据,进行处理后去好拿到没有问题的语句,再写入文件!于是代码就变成这样:

var fs = require('fs');
var readstream = fs.createReadStream('test.js');
var through = require('through');

var size = 0;
var dest = null;
var file = 0;
var cacheData = '';

readstream.setEncoding('utf-8');

readstream.on('data', function (chunk) {
    size += chunk.length / 1000;
    cacheData += chunk;

if (size > 100) {
    // console.log(size, cacheData);
    dest.pause();
    fs.writeFileSync('tet/aim' + file +'.js', cacheData)
    size = 0;
    cacheData = '';
    dest = null;
    file ++;

}
if (!dest) {
    dest = through();
    dest.pipe(fs.createWriteStream('aim/aim' + file +'.js'));
    // dest.pipe();
}
dest.queue(chunk);
}).on('end', function () {
// dest.emit('end');
fs.writeFile('tet/aim' + file +'.js', cacheData, function (err){

    })
})

可以成功的拿到各个数据段进行不怎么随心所欲的处理了(这也就是为什么另外写入文件而不是直接写入stream)。

好吧,剩下的怎么从一段js文件中怎么去拿没有问题的语句了.....

→ →。目前我也没思路。补下正则再回头想!!想的还有其他,如果截取css呢,其他语言呢?

顺便还有几个思路可以进行:

调整js运行的内存 压缩二进制 stream的何时结束

测试代码地址:nodejs-split-file. 另外文本严重参考:stackoverflow

Written on August 4, 2015