You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在内存中创建类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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 05:05:55