UNPKG

@speckle/objectloader2

Version:

This is an updated objectloader for the Speckle viewer written in typescript

123 lines 4.16 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const keyedQueue_js_1 = __importDefault(require("./keyedQueue.js")); /** * Default wait time in milliseconds for processing ongoing tasks during disposal. * This value was chosen to balance responsiveness and CPU usage in typical scenarios. */ const PROCESSING_WAIT_TIME_MS = 100; class BatchingQueue { #queue = new keyedQueue_js_1.default(); #batchSize; #processFunction; #timeoutId = null; #isProcessing = false; #logger; #disposed = false; #batchTimeout; // Helper methods for cross-environment timeout handling #getSetTimeoutFn() { // First check for window object (browser), then fallback to global (node), then just use setTimeout return typeof window !== 'undefined' ? window.setTimeout.bind(window) : typeof global !== 'undefined' ? global.setTimeout : setTimeout; } #getClearTimeoutFn() { // First check for window object (browser), then fallback to global (node), then just use clearTimeout return typeof window !== 'undefined' ? window.clearTimeout.bind(window) : typeof global !== 'undefined' ? global.clearTimeout : clearTimeout; } constructor(params) { this.#batchSize = params.batchSize; this.#processFunction = params.processFunction; this.#batchTimeout = params.maxWaitTime; this.#logger = params.logger || (() => { }); } async disposeAsync() { this.#disposed = true; if (this.#timeoutId) { this.#getClearTimeoutFn()(this.#timeoutId); this.#timeoutId = null; } // Wait for any ongoing processing to finish while (this.#isProcessing) { await new Promise((resolve) => this.#getSetTimeoutFn()(resolve, PROCESSING_WAIT_TIME_MS)); } // After any ongoing flush is completed, there might be items in the queue. // We should flush them. if (this.#queue.size > 0) { await this.#flush(); } } add(key, item) { if (this.#disposed) return; this.#queue.enqueue(key, item); this.#addCheck(); } addAll(keys, items) { if (this.#disposed) return; this.#queue.enqueueAll(keys, items); this.#addCheck(); } #addCheck() { if (this.#disposed) return; if (this.#queue.size >= this.#batchSize) { // Fire and forget, no need to await // eslint-disable-next-line @typescript-eslint/no-floating-promises this.#flush(); } else { if (this.#timeoutId) { this.#getClearTimeoutFn()(this.#timeoutId); } // eslint-disable-next-line @typescript-eslint/no-misused-promises this.#timeoutId = this.#getSetTimeoutFn()(() => this.#flush(), this.#batchTimeout); } } async #flush() { if (this.#timeoutId) { this.#getClearTimeoutFn()(this.#timeoutId); this.#timeoutId = null; } if (this.#isProcessing || this.#queue.size === 0) { return; } this.#isProcessing = true; const batchToProcess = this.#getBatch(this.#batchSize); try { await this.#processFunction(batchToProcess); } catch (error) { this.#logger('Batch processing failed:', error); } finally { this.#isProcessing = false; } this.#addCheck(); } get(id) { return this.#queue.get(id); } count() { return this.#queue.size; } isDisposed() { return this.#disposed; } #getBatch(batchSize) { return this.#queue.spliceValues(0, Math.min(batchSize, this.#queue.size)); } } exports.default = BatchingQueue; //# sourceMappingURL=batchingQueue.js.map