如何在Electron应用中使用node-fetch限制下载速度?
如何在Electron应用中限制fetch下载的速度?
问题描述
我有一段用于Electron应用的文件下载逻辑,简化后如下:
import fetch from "node-fetch"; import path from "path"; import fs from "fs"; const filePath = "C:\\Downloads\\"; const fileName = path.basename(url); const fullFilePath = path.join(filePath, fileName); const response = await fetch(url, options); const fileStream = fs.createWriteStream(fullFilePath); response.body.pipe(fileStream); response.body.on("data", (chunk: Buffer) => { // ... 跟踪进度 }); response.body.on("end", () => { fileStream.end(); fileStream.close(); // ... 上报完成事件 });
现在需要实现允许用户设置最大下载速度的功能,请问该怎么做?
解决方案
方法1:使用现成节流包(推荐)
可以用stream-throttle这个npm包,它专门适配Node.js Stream API来控制流速率,在Electron中可直接使用。
步骤:
- 安装依赖:
npm install stream-throttle
- 修改代码,在响应流和文件流之间插入节流层:
import fetch from "node-fetch"; import path from "path"; import fs from "fs"; import { Throttle } from "stream-throttle"; // 用户设置的最大速度,单位:字节/秒(例:1MB/s = 1024*1024) const maxSpeed = 1024 * 1024; const filePath = "C:\\Downloads\\"; const fileName = path.basename(url); const fullFilePath = path.join(filePath, fileName); const response = await fetch(url, options); // 创建节流流并设定速率 const throttleStream = new Throttle({ rate: maxSpeed }); const fileStream = fs.createWriteStream(fullFilePath); // 先经过节流流再写入文件 response.body.pipe(throttleStream).pipe(fileStream); // 进度跟踪与结束事件逻辑保持不变 response.body.on("data", (chunk: Buffer) => { // ... 跟踪进度 }); response.body.on("end", () => { fileStream.end(); fileStream.close(); // ... 上报完成事件 });
用户调整maxSpeed的值即可修改最大下载速度,逻辑简单且稳定。
方法2:自定义节流Transform流
如果不想依赖第三方包,可手动实现Transform流,通过计算数据块传输延迟来控制速率。
示例代码:
import fetch from "node-fetch"; import path from "path"; import fs from "fs"; import { Transform } from "stream"; class SpeedThrottle extends Transform { constructor(options) { super(options); this.maxSpeed = options.maxSpeed; // 字节/秒 this.bytesSent = 0; this.startTime = Date.now(); } _transform(chunk, encoding, callback) { const now = Date.now(); const elapsed = (now - this.startTime) / 1000; // 已流逝时间(秒) const expectedBytes = this.maxSpeed * elapsed; // 理论应传输字节数 // 计算需要延迟的时间,确保总速率不超限 const delay = (this.bytesSent + chunk.length - expectedBytes) / this.maxSpeed * 1000; if (delay > 0) { setTimeout(() => { this.push(chunk); this.bytesSent += chunk.length; callback(); }, delay); } else { this.push(chunk); this.bytesSent += chunk.length; callback(); } } } // 用户设置的最大速度 const maxSpeed = 1024 * 1024; const filePath = "C:\\Downloads\\"; const fileName = path.basename(url); const fullFilePath = path.join(filePath, fileName); const response = await fetch(url, options); const throttleStream = new SpeedThrottle({ maxSpeed }); const fileStream = fs.createWriteStream(fullFilePath); response.body.pipe(throttleStream).pipe(fileStream); // 后续逻辑保持不变 response.body.on("data", (chunk: Buffer) => { // ... 跟踪进度 }); response.body.on("end", () => { fileStream.end(); fileStream.close(); // ... 上报完成事件 });
这个自定义流会动态计算每个数据块的传输延迟,确保整体速率不超过设定值。
注意事项
- 速率单位是字节/秒,如果用户界面用MB/s显示,需做单位转换(1MB = 1024*1024字节)。
- 两种方法均可在Electron主进程、开启
nodeIntegration的渲染进程中使用。 - 若需动态调整速度,可给节流流添加方法修改
maxSpeed属性(比如自定义流中加setSpeed(newSpeed))。
内容的提问来源于stack exchange,提问作者Dobromir Ivanov
相关产品推荐
相关产品推荐

