UNPKG

@loaders.gl/core

Version:

The core API for working with loaders.gl loaders and writers

96 lines (93 loc) 3.29 kB
// loaders.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import { isBrowser, toArrayBuffer } from '@loaders.gl/loader-utils'; /** * Returns an async iterable that reads from a stream (works in both Node.js and browsers) * @param stream stream to iterator over */ export function makeStreamIterator(stream, options) { return isBrowser ? makeBrowserStreamIterator(stream, options) : makeNodeStreamIterator(stream, options); } /** * Returns an async iterable that reads from a DOM (browser) stream * @param stream stream to iterate from * @see https://jakearchibald.com/2017/async-iterators-and-generators/#making-streams-iterate */ async function* makeBrowserStreamIterator(stream, options) { // WhatWG: stream is supposed to have a `getIterator` method // if (typeof stream.getIterator === 'function') { // return stream.getIterator(); // } // if (typeof stream[Symbol.asyncIterator] === 'function') { // return makeToArrayBufferIterator(stream); // } // In the browser, we first need to get a lock on the stream const reader = stream.getReader(); let nextBatchPromise; try { // eslint-disable-next-line no-constant-condition while (true) { const currentBatchPromise = nextBatchPromise || reader.read(); // Issue a read for an additional batch, while we await the next batch // Idea is to make fetching happen in parallel with processing / parsing if (options?._streamReadAhead) { nextBatchPromise = reader.read(); } // Read from the stream // value is a Uint8Array const { done, value } = await currentBatchPromise; // Exit if we're done if (done) { return; } // Else yield the chunk yield toArrayBuffer(value); } } catch (error) { // TODO - examples makes it look like this should always be called, // but that generates exceptions so only call it if we do not reach the end reader.releaseLock(); } } /** * Returns an async iterable that reads from a DOM (browser) stream * @param stream stream to iterate from * @note Requires Node.js >= 10 */ async function* makeNodeStreamIterator(stream, options) { // Hacky test for node version to ensure we don't call bad polyfills // NODE 10+: stream is an asyncIterator for await (const chunk of stream) { yield toArrayBuffer(chunk); // Coerce each chunk to ArrayBuffer } } /* TODO - remove NODE < 10 * @see https://github.com/bustle/streaming-iterables, MIT license * if (typeof stream[Symbol.asyncIterator] === 'function') { return; } // TODO - check if is this ever used in Node 10+? // eslint-disable-next-line no-constant-condition while (true) { const data = stream.read(); if (data !== null) { yield toArrayBuffer(data); // eslint-disable-next-line no-continue continue; } if (stream._readableState?.ended) { return; } await onceReadable(stream); } async function onceReadable(stream: Readable): Promise<any> { return new Promise((resolve) => { stream.once('readable', resolve); }); } */