自定义writable实现下载文件获得buffer
自定义 writable 实现下载文件为 buffer
writable 是 node.js strem api 中的一个概念, 让我们可以以流(stream)的方式操作数据.更多信息可以参考官方文档
通过 node.js 的http module 可以实现文件下载. 但 http.get 方法返回的结果类型是 stream. 你需要先保存 stream 到文件中, 等待下载结束后再次读取文件获得图片内容. 但有时不方便保存图片到 fs, 你需要直接获得图片的buffer.
继承Writable, 实现 _write 方法
const util = require('util');
const {Writable} = require('stream');
// --------------------------
// CacheWritable
// --------------------------
/**
* 接受下载结果, 缓冲合并为一个buffer后返回
* @extends {NodeJS.WritableStream}
* @param options
* @constructor
*/
function CacheWritable(options) {
this._chunks = [];
Writable.call(this, options);
}
util.inherits(CacheWritable, Writable)
CacheWritable.prototype._write = function (chunk, encoding, cb) {
this._chunks.push(chunk);
cb && cb();
};
CacheWritable.prototype.getBuffer = function () {
let res = Buffer.concat(this._chunks);
this._chunks.splice(0, this._chunks.length);
return res;
};
_write 方法是唯一需要实现的方法. 注意 write 方法的参数 cb 一定要调用, 否则steam会认为_write方法没有完成, 导致 stream 卡住.
把 http.get 封装为Promise
const http = require('http');
const https = require('https');
/**
* 下载
* @param {string} url
* @return {Promise<Buffer>}
*/
async function download(url) {
let act = http;
if (url.indexOf('https://') === 0) {
act = https;
}
return new Promise((resolve, reject) => {
act.get(url, (result) => {
let write = new CacheWritable({emitClose: true});
write.on('finish', () => {
resolve(write.getBuffer());
});
result.pipe(write);
}).on('error', reject);
});
};
这里需要注意
- 需要监听 on(‘finish’) 事件并且返回结果. 因为 close 事件在流关闭时才发出. 如果数据传递完毕了, 但 stream 继续 keepAlive, 那么短时间内你都不会受到 close 方法
- 你不能通过覆盖 writable.end 方法来处理 finish, close 等事件. 阅读node.js 的代码后, 你就会发现 writable.end 已经实现了, 你幷不能通过修改 end 方法来实现自己的事件处理逻辑. 他们只能通过监听 EventEmitter 实现.
其他实现方法
你可以通过 request, concat-stream 这两个模块实现上面的功能.