writablestream在浏览器中无法直接写入本地硬盘,仅能作为流式数据接收端,配合filesystem access api(需用户授权)实现流式保存,或降级为blob下载。

WritableStream 在浏览器中根本不能直接用 fetch() 或 XMLHttpRequest 写入
很多人搜“HTML 实现 WritableStream 写入”,其实是被 Node.js 的 fs.createWriteStream() 带偏了。浏览器环境没有文件系统写入权限,WritableStream 无法直接保存到磁盘或覆盖本地文件——它只能作为流式数据的**接收端管道**,配合 TransformStream、ReadableStream 或 fetch() 的 body(只读)协同工作。
典型可用场景只有两个:1)前端压缩/加密后上传;2)分块处理大文件上传流(如视频切片)。想靠它“在 HTML 页面里写个 log.txt”?做不到。
-
WritableStream必须由支持WritableStream的 API 创建,比如new WritableStream({ write() { ... } }) - 浏览器中唯一能“接入”它的上游是
fetch()的body(仅限POST/PUT请求体),但你不能“往页面里写”,只能“往服务端传” - 试图用
URL.createObjectURL(new WritableStream(...))会报错:TypeError: Failed to construct 'Blob': The object must have a callable 'stream' method
正确创建并消费 WritableStream:必须实现 write()、close() 和 abort()
手动 new 一个 WritableStream 不是为“写 HTML”,而是为了接管数据流的终点行为。比如你想把上传的每一块 chunk 记录到内存 buffer、触发进度条、或转发给另一个 TransformStream。
最小可运行示例:
const writer = new WritableStream({
write(chunk) {
console.log('收到 chunk:', chunk.byteLength, 'bytes');
// 这里可以做:append 到 ArrayBuffer、发给 Web Worker、存进 IndexedDB
},
close() {
console.log('流已关闭,上传完成');
},
abort(reason) {
console.error('流被中断:', reason);
}
});
// 然后用它接收 ReadableStream 数据(例如 FileReader 读取的 blob.stream())
const reader = file.stream().getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
await writer.write(value); // 注意:write() 返回 Promise
}
-
write()必须返回Promise,否则会报TypeError: write method must return a promise -
close()在流自然结束时调用;abort()在writer.abort()或上游出错时触发 - 不要在
write()里直接操作 DOM(比如document.body.innerHTML += ...),大量 chunk 会导致重排卡顿
和 fetch() 配合上传时:WritableStream 只能当 body 的源头,不能当目标
这是最常被误解的一点:你不能“把 fetch 响应写进 WritableStream”,但可以“把 WritableStream 当作 fetch 请求体”。也就是说,WritableStream 是 fetch() 的输入,不是输出。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
例如实现边读边传的大文件上传:
const uploadStream = new WritableStream({
async write(chunk) {
// 每次 write 都触发一次 fetch 分片上传(需服务端支持)
await fetch('/upload/chunk', {
method: 'POST',
body: chunk,
headers: { 'Content-Type': 'application/octet-stream' }
});
}
});
// 把文件流导入这个 WritableStream(需借助 pipeTo)
file.stream().pipeTo(uploadStream);
-
pipeTo()是关键,它把ReadableStream自动连接到WritableStream,无需手写reader.read()循环 - 如果服务端不支持流式接收,
pipeTo()会卡住或报TypeError: Failed to execute 'pipeTo' on 'ReadableStream' - Chrome ≥ 88 支持,Firefox ≥ 105,Safari 16.4+ 才完整支持
pipeTo();旧版需用stream.pipeThrough(new TransformStream())兜底
替代方案更实用:多数“想写 HTML”的需求其实该用 Blob + URL.createObjectURL
如果你的真实目标是“生成一段 HTML 字符串,然后让用户下载 / 预览”,WritableStream 是杀鸡用牛刀。99% 场景下,直接用 Blob 更简单、兼容性更好、无兼容风险。
例如生成并下载 HTML 文件:
const htmlContent = '<h1>Hello</h1>';
const blob = new Blob([htmlContent], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const a = Object.assign(document.createElement('a'), { href: url, download: 'page.html' });
document.body.append(a);
a.click();
URL.revokeObjectURL(url);
-
Blob支持所有现代浏览器,包括 IE10+ - 不需要处理流背压、chunk 边界、promise 链断裂等问题
- 如果内容太大(>500MB),再考虑分块 +
WritableStream+TransformStream组合,但此时你已经需要服务端协作了
真正要用到 WritableStream 的地方,往往意味着你在做流式加密、实时音视频转码、或自定义协议封装——这些都不是“HTML 实现”能一句话带过的,得结合具体传输协议和 worker 架构来设计。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










