当前位置: 首页 > 知识库问答 >
问题:

javascript - 如何在浏览器中使用Worker线程显示下载进度?

嵇浩然
2025-01-10

使用worker线程异步下载项目中的附件,选择100个,下载成100个文件的需求。(目前最多同时下载10个)在modelAndView跳转的对应的jsp中,然后new worker请求下载附件,在worker使用XMLHttpRequest请求下载。然后再worker的监听事件中使用a标签下载附件。
这存在一个问题,只会在下载完成时候的时候浏览器弹出附件下载框,不显示下载进度信息。
怎么显示下载进度信息?示例代码如下:
worker.onmessage = function(){
let blobUrl = new Blob([res.data], {type: 'application/zip'})
let a = document.createElement('a');
let url = window.URL.createObjectURL(blobUrl);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
}

希望和在浏览器中出现下载进度。

共有1个答案

冷翼
2025-01-10

要在浏览器中使用 Web Worker 线程显示下载进度,你需要做几件事情:

  1. 修改 Worker 以返回下载进度:你需要让 Worker 定期发送消息回主线程,报告下载的进度。
  2. 在主线程中更新进度:根据 Worker 发送的进度信息,更新 UI 显示下载进度。

下面是一个修改后的示例,展示如何显示下载进度。这个示例包括在主线程和 Worker 线程之间的通信。

主线程代码(JSP 页面中的 JavaScript)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Download with Progress</title>
</head>
<body>
    <div id="progress-container">
        <div id="progress-bar" style="width: 0%; background-color: green; text-align: center; color: white; padding: 1px;">0%</div>
    </div>

    <script>
        const worker = new Worker('downloadWorker.js');

        // 发送下载任务给 Worker
        const urls = [/* 这里是100个附件的URL数组 */];
        const batchSize = 10;  // 同时下载的最大数量
        let currentIndex = 0;

        function startDownloads() {
            for (let i = 0; i < batchSize && currentIndex < urls.length; i++) {
                worker.postMessage({ url: urls[currentIndex], index: currentIndex });
                currentIndex++;
            }
        }

        worker.onmessage = function(event) {
            const { index, progress, data, fileName } = event.data;
            if (progress !== undefined) {
                const totalDownloads = urls.length;
                const overallProgress = ((index + 1) * batchSize + progress) / (totalDownloads * 100);
                const progressBar = document.getElementById('progress-bar');
                progressBar.style.width = `${Math.min(overallProgress * 100, 100)}%`;
                progressBar.textContent = `${Math.min(overallProgress * 100, 100).toFixed(2)}%`;
            } else if (data && fileName) {
                const blobUrl = URL.createObjectURL(new Blob([data], { type: 'application/zip' }));
                const a = document.createElement('a');
                a.href = blobUrl;
                a.download = fileName;
                a.click();
                URL.revokeObjectURL(blobUrl);

                // 如果有更多文件需要下载,继续下载
                if (currentIndex < urls.length) {
                    startDownloads();
                }
            }
        };

        // 开始下载
        startDownloads();
    </script>
</body>
</html>

Worker 线程代码(downloadWorker.js)

self.onmessage = function(event) {
    const { url, index } = event.data;
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob';

    xhr.onprogress = function(e) {
        if (e.lengthComputable) {
            const progress = Math.round((e.loaded * 100) / e.total);
            self.postMessage({ index, progress });
        }
    };

    xhr.onload = function() {
        if (xhr.status === 200) {
            self.postMessage({ index, data: xhr.response, fileName: `file_${index}.zip` });
        } else {
            console.error(`Failed to download file ${index}: ${xhr.statusText}`);
        }
    };

    xhr.onerror = function() {
        console.error(`Error downloading file ${index}`);
    };

    xhr.send();
};

解释

  1. 主线程

    • 创建一个进度条容器。
    • 使用 Web Worker 发送下载任务。
    • 监听 Worker 发送的消息,更新进度条。
    • 下载完成后,创建 Blob URL 并模拟点击 <a> 标签下载文件。
    • 如果还有文件需要下载,继续发送下载任务。
  2. Worker 线程

    • 接收下载任务(URL 和索引)。
    • 使用 XMLHttpRequest 发起下载请求。
    • onprogress 事件中,计算并发送下载进度给主线程。
    • onload 事件中,发送下载的数据和文件名给主线程。

这样,你就可以在浏览器中显示下载进度了。

 类似资料:
  • 我在下面指定的PHP中编写了一个下载脚本,我的脚本正在正确下载文件,但是我感觉浏览器(chrome)进度条没有定期正确更新。 我的文件大小为320MB,下载该文件时进度随机更新为"11MB,76MB,200Mb 在大多数网站中,下载进度更新都是在每次MB之后持续进行的,所以我想知道我们如何控制进度更新间隔,可能是通过发送一些额外的头或其他东西。 我想通过不断更新进度来改善用户体验,所以任何人请帮助

  • 问题内容: 为了使IM Client始终保持登录状态,Facebook通过在将页面插入文档之前使用AJAX加载页面来避免整个页面加载。 但是,在Facebook AJAX请求期间,浏览器似乎正在加载。重新加载按钮变为X,浏览器中内置的进度指示器指示正在加载/正在等待等) 我已经能够成功实现基于AJAX的导航,但是我的浏览器没有显示任何加载迹象(由于请求是异步的),Facebook如何做到这一点?

  • 问题内容: 在我的servlet中,我使用下面的代码在浏览器中打开PDF文件,但是,它显示了一个下载对话框。 我做错了什么? 问题答案: 你可以尝试用

  • 问题内容: 我是expressjs的新手,我无法使用数据对象发送响应。二进制内容在浏览器中可见。给我建议如何处理? 问题答案: 我测试了您的代码,它在chrome中对我有效,但有一个更改:更改为 编辑:由于您似乎认为仅POST服务器是一个好主意,请阅读:http : //net.tutsplus.com/tutorials/other/a-beginners-introduction-to-htt

  • 在我的php文件中,我有以下内容来创建一个带有FPDF库的PDF: 但是请求是响应这个,而不是打开一个保存对话框来保存我的PDF。 %PDF-1.3 3 0 obj<>endobj 4 0 obj<>stream x 3 R@2π35 W(çR qπw 3 t04多30 pispéz*[(hx·ääää+çó)·(j*dé7 w endstream endobj 1 0 obj /xobject<

  • 我正在使用Jersey实施Rest服务。我想在浏览器上显示JSON,但我得到的是XML。 我感谢你的帮助。

  • 我使用下载管理器api下载大文件,我也实现了。但问题是,下载进度通知显示在状态栏中。但是我想用进度条在活动中显示通知。有人做过吗,如果有请帮帮我。

  • 问题内容: 单击图像后,是否可以将其下载(没有右键单击 将图像另存为 )? 我正在使用一个小的Javascript函数来调用下载页面: 在download.php页面中,我有类似以下内容: 但这是行不通的。我究竟做错了什么? 提前致谢! 问题答案: 使用 application / octet- stream 代替 image / jpg : 如果在应用程序/八位字节流内容类型的响应中使用[Con