获取 blob 的进度 javascript
Progress for a fetch blob javascript
我正在尝试执行 javascript 提取以使用提取获取视频文件。我能够下载文件并获取 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:Body 已被消耗”。我看到 reader.read() 可能正在这样做。我怎样才能得到接收到的数据量,然后在它的末尾得到一个 blob URL?
谢谢。
更新:
我的第一次尝试是在下载块时收集它们,然后将它们放回原处,占用大量内存(视频大小的 2-3 倍)。使用 ReadableStream 的内存占用要低得多(对于 1.1GB 的 mkv,内存使用量徘徊在 150MB 左右)。代码主要改编自这里的代码片段,我只做了很少的修改:
<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,然后在组合块时飙升到大约 3.5Gb。视频开始播放后,选项卡的内存使用量会回落至约 200MB,但 Chrome 的总体使用量仍超过 1GB。
无需调用 response.blob()
来获取 blob,您可以通过累积视频的每个块 (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 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:Body 已被消耗”。我看到 reader.read() 可能正在这样做。我怎样才能得到接收到的数据量,然后在它的末尾得到一个 blob URL?
谢谢。
更新:
我的第一次尝试是在下载块时收集它们,然后将它们放回原处,占用大量内存(视频大小的 2-3 倍)。使用 ReadableStream 的内存占用要低得多(对于 1.1GB 的 mkv,内存使用量徘徊在 150MB 左右)。代码主要改编自这里的代码片段,我只做了很少的修改:
<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,然后在组合块时飙升到大约 3.5Gb。视频开始播放后,选项卡的内存使用量会回落至约 200MB,但 Chrome 的总体使用量仍超过 1GB。
无需调用 response.blob()
来获取 blob,您可以通过累积视频的每个块 (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'})