javascript - 获取 blob javascript 的进度

标签 javascript fetch blob

我正在尝试使用 fetch 执行 javascript fetch 来抓取视频文件。我能够下载文件并获取 blob URL,但我似乎无法在下载时获取进度。

我试过这个:

    let response = await fetch('test.mp4');
    
    const reader = response.body.getReader();
    
    const contentLength=response.headers.get('Content-Length');
    
    let receivedLength = 0; 
    d=document.getElementById('progress_bar');
    while(true) 
    {
        const {done, value} = await reader.read();
        
        if (done) 
        {
            break;
        }
        receivedLength += value.length;
        d.innerHTML="Bytes loaded:"+receivedLength;
    }
    
    const blob = await response.blob();
    
    var vid=URL.createObjectURL(blob);

问题是我收到“Response.blob:主体已被消耗”。我看到 reader.read() 可能正在这样做。我如何只获取接收到的数据量,然后在其末尾获取一个 blob URL?

谢谢。

最佳答案

更新:

我的第一次尝试是在下载 block 时收集它们,然后将它们放回一起,占用大量内存(视频大小的 2-3 倍)。使用 ReadableStream 的内存占用要低得多(对于 1.1GB 的 mkv,内存使用量徘徊在 150MB 左右)。代码主要改编自这里的代码片段,我只做了很少的修改:

https://github.com/AnthumChris/fetch-progress-indicators/blob/master/fetch-basic/supported-browser.js

<div id="progress_bar"></div>
<video id="video_player"></video>
    const elProgress = document.getElementById('progress_bar'),
        player = document.getElementById('video_player');

    function getVideo2() {
        let contentType = 'video/mp4';
        fetch('$pathToVideo.mp4')
            .then(response => {

                const contentEncoding = response.headers.get('content-encoding');
                const contentLength = response.headers.get(contentEncoding ? 'x-file-size' : 'content-length');
                contentType = response.headers.get('content-type') || contentType;
                if (contentLength === null) {
                    throw Error('Response size header unavailable');
                }

                const total = parseInt(contentLength, 10);
                let loaded = 0;

                return new Response(
                    new ReadableStream({
                        start(controller) {
                            const reader = response.body.getReader();

                            read();

                            function read() {
                                reader.read().then(({done, value}) => {
                                    if (done) {
                                        controller.close();
                                        return;
                                    }
                                    loaded += value.byteLength;
                                    progress({loaded, total})
                                    controller.enqueue(value);
                                    read();
                                }).catch(error => {
                                    console.error(error);
                                    controller.error(error)
                                })
                            }
                        }
                    })
                );
            })
            .then(response => response.blob())
            .then(blob => {
                let vid = URL.createObjectURL(blob);
                player.style.display = 'block';
                player.type = contentType;
                player.src = vid;
                elProgress.innerHTML += "<br /> Press play!";
            })
            .catch(error => {
                console.error(error);
            })
    }

    function progress({loaded, total}) {
        elProgress.innerHTML = Math.round(loaded / total * 100) + '%';
    }

First Attempt(较差,适合较小的文件)

我原来的方法。对于 1.1GB 的 mkv,在下载文件时内存使用量上升到 1.3GB,然后在组合 block 时飙升到大约 3.5Gb。视频开始播放后,标签页的内存使用量会回落至约 200MB,但 Chrome 的整体使用量仍会超过 1GB。

无需调用 response.blob() 来获取 blob,您可以通过累积视频的每个 block (value)自行构建 blob。改编自此处的示例:https://javascript.info/fetch-progress#0d0g7tutne

        //...
        receivedLength += value.length;
        chunks.push(value);
        //...
        // ==> put the chunks into a Uint8Array that the Blob constructor can use
        let Uint8Chunks = new Uint8Array(receivedLength), position = 0;
        for (let chunk of chunks) {
            Uint8Chunks.set(chunk, position);
            position += chunk.length;
        }

        // ==> you may want to get the mimetype from the content-type header
        const blob = new Blob([Uint8Chunks], {type: 'video/mp4'})

关于javascript - 获取 blob javascript 的进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67362823/

相关文章:

python-2.7 - 将图像中的 Blob 识别为车辆的 Blob

javascript - 使用 jQuery 执行动态传递的函数调用

php - 从现有选项中预选择“选择”或多选选项,而不是添加和选择新选项

javascript - 从 FastAPI 获取文件时如何使用浏览器缓存?

php - 如何使用 PHP 从具有其他列文本的表格中获取图像

python - 无法使用Python将PDF文件插入MySQL数据库

javascript - 在javascript中循环多维数组会跳过数据吗?

javascript - HTML 标签 <em> 仅出现在实时网站上

javascript - 如何在客户端(AngularJS)加密密码,将其发送到服务器(expressJS)并在服务器上解密?

javascript - POST 请求适用于 Postman,但不适用于 axios 或 .fetch()