From 0ec243bcd10b8d1cb4b7ee0b54a9f45afac7bfd7 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Mon, 6 Nov 2023 09:45:20 +0100 Subject: [PATCH] perf: optimize Readable.dump --- lib/api/readable.js | 50 +++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/lib/api/readable.js b/lib/api/readable.js index d106568cd4b..0c31f455622 100644 --- a/lib/api/readable.js +++ b/lib/api/readable.js @@ -16,6 +16,8 @@ const kBody = Symbol('kBody') const kAbort = Symbol('abort') const kContentType = Symbol('kContentType') +const noop = () => {} + module.exports = class BodyReadable extends Readable { constructor ({ resume, @@ -152,34 +154,42 @@ module.exports = class BodyReadable extends Readable { async dump (opts) { let limit = opts && Number.isFinite(opts.limit) ? opts.limit : 262144 const signal = opts && opts.signal - const abortFn = () => { - this.destroy() - } + let signalListenerCleanup if (signal) { if (typeof signal !== 'object' || !('aborted' in signal)) { throw new InvalidArgumentError('signal must be an AbortSignal') } util.throwIfAborted(signal) - signalListenerCleanup = util.addAbortListener(signal, abortFn) } - try { - for await (const chunk of this) { - util.throwIfAborted(signal) - limit -= Buffer.byteLength(chunk) - if (limit < 0) { - return - } - } - } catch { - util.throwIfAborted(signal) - } finally { - if (typeof signalListenerCleanup === 'function') { - signalListenerCleanup() - } else if (signalListenerCleanup) { - signalListenerCleanup[Symbol.dispose]() - } + + if (this.closed) { + return Promise.resolve(null) } + + return new Promise((resolve, reject) => { + signalListenerCleanup = util.addAbortListener(signal, () => { + this.destroy() + }) + + this + .on('close', function () { + signalListenerCleanup() + if (signal?.aborted) { + reject(signal.reason || Object.assign(new Error('The operation was aborted'), { name: 'AbortError' })) + } else { + resolve(null) + } + }) + .on('error', noop) + .on('data', function (chunk) { + limit -= chunk.length + if (limit <= 0) { + this.destroy() + } + }) + .resume() + }) } }