如何在内存中创建类fs.createWriteStream的JS WritableStream(ServiceWorker场景)
解决方案
核心思路
ServiceWorker环境不支持Node.js的fs模块,需通过Web标准可写流或自定义模拟Node.js流接口的对象,将库导出的数据写入预先创建的字节数组Out中。
方案1:使用Web Streams API的WritableStream
如果JsLib.export支持Web标准的WritableStream,可直接实现自定义写入逻辑:
// 维护写入偏移量,确保数据连续写入Out数组 let writeOffset = 0; // 定义自定义写入接收器 const memorySink = { write(chunk) { // 将传入的二进制数据转为Uint8Array(多数库导出的二进制数据为该类型) const data = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk); // 可选:检查Out数组容量是否足够,避免溢出 if (writeOffset + data.length > Out.length) { throw new Error('Out数组容量不足,无法容纳导出数据'); } Out.set(data, writeOffset); writeOffset += data.length; }, close() { // 写入完成后可重置偏移量,方便后续复用 // writeOffset = 0; }, abort(reason) { console.error('导出失败:', reason); } }; // 创建内存可写流 const memoryWriteStream = new WritableStream(memorySink); // 对接JsLib.export JsLib.export(result, memoryWriteStream);
方案2:模拟Node.js风格的Writable流
如果JsLib.export仅兼容Node.js的流接口(依赖write/end方法或事件),可自定义模拟类:
class MemoryWritable { constructor(targetArray) { this.target = targetArray; this.offset = 0; this.closed = false; this.listeners = {}; // 模拟事件监听 } // 模拟Node.js流的write方法 write(chunk) { if (this.closed) throw new Error('流已关闭'); const data = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk); if (this.offset + data.length > this.target.length) { throw new Error('目标数组容量不足'); } this.target.set(data, this.offset); this.offset += data.length; return true; // Node.js流返回true表示可继续写入 } // 模拟Node.js流的end方法 end(chunk) { if (chunk) this.write(chunk); this.closed = true; // 触发finish事件(若库依赖该事件) this.emit('finish'); } // 模拟事件监听 on(event, callback) { if (!this.listeners[event]) this.listeners[event] = []; this.listeners[event].push(callback); } // 模拟事件触发 emit(event) { this.listeners[event]?.forEach(cb => cb()); } } // 创建实例并对接库 const memoryWriteStream = new MemoryWritable(Out); JsLib.export(result, memoryWriteStream);
扩展运算符错误的解决
你遇到的"A spread argument must either have a tuple type or be passed to a rest parameter"错误,是因为尝试用...扩展非可迭代对象或类型不匹配的值。解决方式:
- 放弃用扩展运算符复制二进制数据,直接使用TypedArray的
set方法(如上述代码);如果Out是非标准字节数组,可改用循环逐个赋值:write(chunk) { for (let i = 0; i < chunk.length; i++) { this.target[this.offset + i] = chunk[i]; } this.offset += chunk.length; }
注意事项
- 确保
Out数组的大小足够容纳导出的PDF数据,否则会抛出溢出错误; - 如果
JsLib.export返回Promise,需等待其完成后再使用Out数组:await JsLib.export(result, memoryWriteStream); // 后续处理Out数组
内容的提问来源于stack exchange,提问作者Viacheslav
相关产品推荐
相关产品推荐

