@loaders.gl/core
Version:
The core API for working with loaders.gl loaders and writers
60 lines (59 loc) • 2.15 kB
JavaScript
// loaders.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
// Forked from github AnthumChris/fetch-progress-indicators under MIT license
/**
* Intercepts the Response stream and creates a new Response
*/
export async function fetchProgress(response, onProgress, // TODO better callback types
onDone = () => { }, onError = () => { }) {
response = await response;
if (!response.ok) {
// ERROR checking needs to be done separately
return response;
}
const body = response.body;
if (!body) {
// 'ReadableStream not yet supported in this browser.
return response;
}
const contentLength = response.headers.get('content-length') || 0;
const totalBytes = contentLength ? parseInt(contentLength) : 0;
if (!(totalBytes > 0)) {
return response;
}
// Currently override only implemented in browser
if (typeof ReadableStream === 'undefined' || !body.getReader) {
return response;
}
// Create a new stream that invisbly wraps original stream
const progressStream = new ReadableStream({
async start(controller) {
const reader = body.getReader();
await read(controller, reader, 0, totalBytes, onProgress, onDone, onError);
}
});
return new Response(progressStream);
}
// Forward to original streams controller
// TODO - this causes a crazy deep "async stack"... rewrite as async iterator?
// eslint-disable-next-line max-params
async function read(controller, reader, loadedBytes, totalBytes, onProgress, onDone, onError) {
try {
const { done, value } = await reader.read();
if (done) {
onDone();
controller.close();
return;
}
loadedBytes += value.byteLength;
const percent = Math.round((loadedBytes / totalBytes) * 100);
onProgress(percent, { loadedBytes, totalBytes });
controller.enqueue(value);
await read(controller, reader, loadedBytes, totalBytes, onProgress, onDone, onError);
}
catch (error) {
controller.error(error);
onError(error);
}
}