如果需要下载视频,可以通过 xhr 或者是 fetch 来下载,xhr 自带了 api 来监听下载的进度, fetch 也可以使用流式的接口来监听下载进度。
但是这两种方式都有一个问题,就是下载的内容会先保存在内存中,然后再触发下载来保存在磁盘中,这样一来效率比较低,而且文件如果很大那根本就无法实现。
如果是使用传统的下载方式,那么下载进度条只能在浏览器的下载管理中查看。
那怎么可以做到既不先把数据保存在内存中,也能在页面上显示下载进度
负责启动下载过程,处理从Service Worker接收的消息,并更新下载进度或处理下载完成的逻辑。
// 记录已下载的字节数,用于断点续传
let downloadedSize = 0;
// 开始下载函数
function startDownload(url) {
// 确保 Service Worker 已经注册并准备好
navigator.serviceWorker.ready.then(registration => {
// 向 Service Worker 发送消息,包含下载 URL 和分片大小
registration.active.postMessage({ url, chunkSize: 2 * 1024 * 1024, downloadedSize });
});
}
// 监听来自 Service Worker 的消息
navigator.serviceWorker.addEventListener('message', event => {
if (event.data.type === 'progress') {
// 更新下载进度
console.log(`Download progress: ${event.data.progress.toFixed(2)}%`);
document.getElementById('progress').innerText = `Download progress: ${event.data.progress.toFixed(2)}%`;
} else if (event.data.type === 'complete') {
// 下载完成,创建下载链接并触发下载
const link = document.createElement('a');
link.href = event.data.url;
link.download = 'video.mp4';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else if (event.data.type === 'resume') {
// 更新已下载的字节数,用于断点续传
downloadedSize = event.data.downloadedSize;
}
});
// 开始下载
startDownload('video_url');
负责分片下载文件,记录已下载的进度,并将下载进度和完成消息传回主线程。
// 监听来自主线程的消息
self.addEventListener('message', async (event) => {
const { url, chunkSize, downloadedSize } = event.data;
// 获取文件总大小
const response = await fetch(url, { method: 'HEAD' });
const totalSize = parseInt(response.headers.get('Content-Length'), 10);
let currentDownloadedSize = downloadedSize;
const chunks = [];
// 分片下载文件
for (let start = downloadedSize; start < totalSize; start += chunkSize) {
const end = Math.min(start + chunkSize - 1, totalSize - 1);
const chunk = await fetch(url, {
headers: { 'Range': `bytes=${start}-${end}` }
}).then(res => res.blob());
chunks.push(chunk);
currentDownloadedSize += chunk.size;
// 向主线程发送下载进度
self.clients.matchAll().then(clients => {
clients.forEach(client => client.postMessage({
type: 'progress',
progress: (currentDownloadedSize / totalSize) * 100,
downloadedSize: currentDownloadedSize
}));
});
}
// 合并所有分片并创建 Blob
const blob = new Blob(chunks);
const link = self.registration.scope + 'video.mp4';
const cache = await caches.open('video-cache');
await cache.put(link, new Response(blob));
// 向主线程发送下载完成消息
self.clients.matchAll().then(clients => {
clients.forEach(client => client.postMessage({
type: 'complete',
url: link
}));
});
});
负责显示下载进度,并包含主线程的JavaScript代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Download Progress</title>
</head>
<body>
<!-- 显示下载进度 -->
<div id="progress">Download progress: 0%</div>
<script src="index.js"></script>
</body>
</html>
主线程 (index.js):
Service Worker (sw.js):
HTML:
### 回答
要在 web 端监听下载进度百分比而不先将数据保存在内存中,你可以使用 Service Workers 结合 `fetch` API 的流式下载。Service Workers 在后台运行脚本,独立于网页,能够处理网络请求,包括下载文件。
#### 步骤概述
1. **注册 Service Worker**:
在你的网页中注册一个 Service Worker,它将处理下载请求。
2. **在 Service Worker 中处理下载**:
使用 `fetch` API 发起下载请求,并通过 `ReadableStream` 接口处理响应数据。同时,你可以通过 `postMessage` 方法将下载进度信息发送回主线程。
3. **在主线程中更新进度**:
监听来自 Service Worker 的消息,并更新页面上的下载进度条。
#### 示例代码
**主线程(HTML + JavaScript)**:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Download Progress</title>
</head>
<body>
<button id="downloadBtn">Download Video</button>
<progress id="progressBar" value="0" max="100" style="width: 100%;"></progress>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js').then(function(registration) {
console.log('Service Worker registered with scope:', registration.scope);
}).catch(function(error) {
console.log('Service Worker registration failed:', error);
});
}
document.getElementById('downloadBtn').addEventListener('click', function() {
navigator.serviceWorker.controller.postMessage({ action: 'download', url: 'path/to/video.mp4' });
});
navigator.serviceWorker.controller.addEventListener('message', function(event) {
if (event.data.action === 'progress') {
document.getElementById('progressBar').value = event.data.progress;
} else if (event.data.action === 'done') {
alert('Download complete!');
}
});
</script>
</body>
</html>
**Service Worker(service-worker.js)**:
self.addEventListener('message', function(event) {
if (event.data.action === 'download') {
const url = event.data.url;
const responseType = 'blob';
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.body.getReader();
})
.then(reader => {
const totalSize = response.headers.get('Content-Length') || 1; // Fallback to 1 to avoid division by zero
let loaded = 0;
function read() {
reader.read().then(({ done, value }) => {
if (done) {
self.postMessage({ action: 'done' });
return;
}
loaded += value.byteLength;
const progress = Math.round((loaded / totalSize) * 100);
self.postMessage({ action: 'progress', progress });
read(); // Recursive call to read the next chunk
}).catch(error => {
console.error('Error reading stream:', error);
});
}
read();
})
.catch(error => {
console.error('Error downloading file:', error);
});
}
});
#### 说明
- **Service Worker 注册**:在网页中注册 Service Worker,以便它可以处理后台任务。
- **消息传递**:通过 `postMessage` 方法在 Service Worker 和主线程之间传递消息,包括下载请求和进度更新。
- **流式下载**:使用 `fetch` API 和 `ReadableStream` 接口进行流式下载,避免将整个文件加载到内存中。
- **进度更新**:在 Service Worker 中读取文件流时,计算并发送下载进度到主线程,以便更新页面上的进度条。
这种方法允许你在不将下载内容首先保存在内存中的情况下,在页面上显示下载进度。
本文向大家介绍Android实现百分比下载进度条效果,包括了Android实现百分比下载进度条效果的使用技巧和注意事项,需要的朋友参考一下 现在很多APP中都会集成下载功能,所以有一个方便好看又实用的进度条来展示下载进度很有必要,也能提高用户体验,在这里我就把项目里的下载进度条抽取出来分享给大家,话不多说,先看效果图: 这个进度条是自定义的一个View,其中有一个自定义属性就是百分比文字的大小(也
本文向大家介绍使用Retrofit下载文件并实现进度监听的示例,包括了使用Retrofit下载文件并实现进度监听的示例的使用技巧和注意事项,需要的朋友参考一下 1.前言 最近要做一个带进度条下载文件的功能,网上看了一圈,发现好多都是基于 OkHttpClient 添加拦截器来实现的,个人觉得略显复杂,所以还是采用最简单的方法来实现:基于文件写入来进行进度的监听。 2.实现步骤 2.1 设计监听接口
本文向大家介绍android中DownloadManager实现版本更新,监听下载进度实例,包括了android中DownloadManager实现版本更新,监听下载进度实例的使用技巧和注意事项,需要的朋友参考一下 DownloadManager简介 DownloadManager是Android 2.3(API level 9)用系统服务(Service)的方式提供了DownloadManage
我试图在请求中添加客户端进度条。理想的做法是获取请求头大小并接收 我对了解不多,但据我所知,必须启动请求才能实现这一点(请参见此处) PS1.虽然主要的范围为这,是一个文件上传进度条,我希望能够申请的全部请求大小。PS2.我知道有几个图书馆免费提供这一点,但ATM我不想使用任何。
问题内容: 如何使用进度条显示页面的加载百分比?…(类似于它们在Flash中的显示方式) 谢谢 问题答案: 不可能(在IE8和FF3和Opera上,没有插件或扩展名)。如果要实际加载百分比,请包括HTML + Javascript +样式表+图片。您只能检测到页面中加载了多少文件(此技术只能检测到图像和javascript)。
本文向大家介绍如何用Node监听80端口?相关面试题,主要包含被问及如何用Node监听80端口?时的应答技巧和注意事项,需要的朋友参考一下 这题有陷阱!在类Unix系统中你不应该去监听80端口,因为这需要超级用户权限。因此不推荐让你的应用直接监听这个端口。 目前,如果你一定要让你的应用80端口的话,你可以有通过在Node应用的前方再添加一层反向代理(例如nginx)来实现,如下图。否则,建议你直接
我有一个文件 这个类是一个独立的文件, 这个类被多个其他文件所引用 如何提前hack这个类 让他每次实例化的时候回调给我, 让我知道他实例化了从而运行一些实例化的代码
fetch 方法允许去跟踪 下载 进度。 请注意:到目前为止,fetch 方法无法跟踪 上传 进度。对于这个目的,请使用 XMLHttpRequest,我们在后面章节会讲到。 要跟踪下载进度,我们可以使用 response.body 属性。它是 ReadableStream —— 一个特殊的对象,它可以逐块(chunk)提供 body。在 Streams API 规范中有对 ReadableStr