From da22146b95dc1d7965874a57cedf4c16df56d6c6 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 24 Apr 2021 12:36:01 +0200 Subject: [PATCH 1/2] Replace a bunch of `Array.prototype.forEach()` cases with `for...of` loops instead Using `for...of` is a modern and generally much nicer pattern, since it gets rid of unnecessary callback-functions. (In a couple of spots, a "regular" `for` loop had to be used.) --- src/core/evaluator.js | 4 ++-- src/core/function.js | 13 +++++++------ src/core/worker.js | 4 ++-- src/core/worker_stream.js | 5 ++--- src/display/annotation_layer.js | 12 ++++++------ src/display/api.js | 4 ++-- src/display/fetch_stream.js | 5 ++--- src/display/font_loader.js | 4 ++-- src/display/network.js | 25 ++++++++++++------------- src/display/node_stream.js | 6 ++---- src/display/svg.js | 4 ++-- src/display/text_layer.js | 23 ++++++++++++----------- src/display/transport_stream.js | 19 +++++++++---------- web/ui_utils.js | 10 +++++----- 14 files changed, 67 insertions(+), 71 deletions(-) diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 678998552..46c2cb3f1 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -1394,9 +1394,9 @@ class PartialEvaluator { ) { const groupIds = []; if (Array.isArray(optionalContentGroups)) { - optionalContent.get("OCGs").forEach(ocg => { + for (const ocg of optionalContentGroups) { groupIds.push(ocg.toString()); - }); + } } else { // Dictionary, just use the obj id. groupIds.push(optionalContentGroups.objId); diff --git a/src/core/function.js b/src/core/function.js index a1f05114d..02756388b 100644 --- a/src/core/function.js +++ b/src/core/function.js @@ -1337,13 +1337,14 @@ var PostScriptCompiler = (function PostScriptCompilerClosure() { } var result = []; - instructions.forEach(function (instruction) { - var statementBuilder = new ExpressionBuilderVisitor(); + for (const instruction of instructions) { + const statementBuilder = new ExpressionBuilderVisitor(); instruction.visit(statementBuilder); result.push(statementBuilder.toString()); - }); - stack.forEach(function (expr, i) { - var statementBuilder = new ExpressionBuilderVisitor(); + } + for (let i = 0, ii = stack.length; i < ii; i++) { + const expr = stack[i], + statementBuilder = new ExpressionBuilderVisitor(); expr.visit(statementBuilder); var min = range[i * 2], max = range[i * 2 + 1]; @@ -1359,7 +1360,7 @@ var PostScriptCompiler = (function PostScriptCompilerClosure() { out.unshift("dest[destOffset + ", i, "] = "); out.push(";"); result.push(out.join("")); - }); + } return result.join("\n"); } } diff --git a/src/core/worker.js b/src/core/worker.js index a19a3c410..51bc133f1 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -785,10 +785,10 @@ class WorkerMessageHandler { cancelXHRs(new AbortException("Worker was terminated.")); } - WorkerTasks.forEach(function (task) { + for (const task of WorkerTasks) { waitOn.push(task.finished); task.terminate(); - }); + } return Promise.all(waitOn).then(function () { // Notice that even if we destroying handler, resolved response promise diff --git a/src/core/worker_stream.js b/src/core/worker_stream.js index 204c08f80..f3baa72ea 100644 --- a/src/core/worker_stream.js +++ b/src/core/worker_stream.js @@ -43,10 +43,9 @@ class PDFWorkerStream { if (this._fullRequestReader) { this._fullRequestReader.cancel(reason); } - const readers = this._rangeRequestReaders.slice(0); - readers.forEach(function (reader) { + for (const reader of this._rangeRequestReaders.slice(0)) { reader.cancel(reason); - }); + } } } diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index c2a4c8508..6e25f44b6 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -343,9 +343,9 @@ class AnnotationElement { assert(this.quadrilaterals, "Missing quadrilaterals during rendering"); } - this.quadrilaterals.forEach(quadrilateral => { + for (const quadrilateral of this.quadrilaterals) { quadrilateral.className = className; - }); + } return this.quadrilaterals; } @@ -1445,11 +1445,11 @@ class PopupElement { } // Attach the event listeners to the trigger element. - this.trigger.forEach(element => { + for (const element of this.trigger) { element.addEventListener("click", this._toggle.bind(this)); element.addEventListener("mouseover", this._show.bind(this, false)); element.addEventListener("mouseout", this._hide.bind(this, false)); - }); + } popup.addEventListener("click", this._hide.bind(this, true)); wrapper.appendChild(popup); @@ -2104,9 +2104,9 @@ class AnnotationLayer { `[data-annotation-id="${data.id}"]` ); if (elements) { - elements.forEach(element => { + for (const element of elements) { element.style.transform = transform; - }); + } } } parameters.div.hidden = false; diff --git a/src/display/api.js b/src/display/api.js index b05fd4641..1adf7d2ad 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -2289,11 +2289,11 @@ class WorkerTransport { const waitOn = []; // We need to wait for all renderings to be completed, e.g. // timeout/rAF can take a long time. - this.pageCache.forEach(function (page) { + for (const page of this.pageCache) { if (page) { waitOn.push(page._destroy()); } - }); + } this.pageCache.length = 0; this.pagePromises.length = 0; // Allow `AnnotationStorage`-related clean-up when destroying the document. diff --git a/src/display/fetch_stream.js b/src/display/fetch_stream.js index ebfc5f954..40be6dd05 100644 --- a/src/display/fetch_stream.js +++ b/src/display/fetch_stream.js @@ -91,10 +91,9 @@ class PDFFetchStream { if (this._fullRequestReader) { this._fullRequestReader.cancel(reason); } - const readers = this._rangeRequestReaders.slice(0); - readers.forEach(function (reader) { + for (const reader of this._rangeRequestReaders.slice(0)) { reader.cancel(reason); - }); + } } } diff --git a/src/display/font_loader.js b/src/display/font_loader.js index 63d680e7d..619915ecc 100644 --- a/src/display/font_loader.js +++ b/src/display/font_loader.js @@ -61,9 +61,9 @@ class BaseFontLoader { } clear() { - this.nativeFontFaces.forEach(nativeFontFace => { + for (const nativeFontFace of this.nativeFontFaces) { this._document.fonts.delete(nativeFontFace); - }); + } this.nativeFontFaces.length = 0; if (this.styleElement) { diff --git a/src/display/network.js b/src/display/network.js index 41ce45b4c..e415a419b 100644 --- a/src/display/network.js +++ b/src/display/network.js @@ -259,10 +259,9 @@ class PDFNetworkStream { if (this._fullRequestReader) { this._fullRequestReader.cancel(reason); } - const readers = this._rangeRequestReaders.slice(0); - readers.forEach(function (reader) { + for (const reader of this._rangeRequestReaders.slice(0)) { reader.cancel(reason); - }); + } } } @@ -348,9 +347,9 @@ class PDFNetworkStreamFullRequestReader { if (this._cachedChunks.length > 0) { return; } - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } this._requests = []; } @@ -359,9 +358,9 @@ class PDFNetworkStreamFullRequestReader { const exception = createResponseStatusError(status, url); this._storedError = exception; this._headersReceivedCapability.reject(exception); - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.reject(exception); - }); + } this._requests = []; this._cachedChunks = []; } @@ -414,9 +413,9 @@ class PDFNetworkStreamFullRequestReader { cancel(reason) { this._done = true; this._headersReceivedCapability.reject(reason); - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } this._requests = []; if (this._manager.isPendingRequest(this._fullRequestId)) { this._manager.abortRequest(this._fullRequestId); @@ -457,9 +456,9 @@ class PDFNetworkStreamRangeRequestReader { this._queuedChunk = chunk; } this._done = true; - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } this._requests = []; this._close(); } @@ -492,9 +491,9 @@ class PDFNetworkStreamRangeRequestReader { cancel(reason) { this._done = true; - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } this._requests = []; if (this._manager.isPendingRequest(this._requestId)) { this._manager.abortRequest(this._requestId); diff --git a/src/display/node_stream.js b/src/display/node_stream.js index ff8c75ad5..ba6f668fd 100644 --- a/src/display/node_stream.js +++ b/src/display/node_stream.js @@ -98,11 +98,9 @@ class PDFNodeStream { if (this._fullRequestReader) { this._fullRequestReader.cancel(reason); } - - const readers = this._rangeRequestReaders.slice(0); - readers.forEach(function (reader) { + for (const reader of this._rangeRequestReaders.slice(0)) { reader.cancel(reason); - }); + } } } diff --git a/src/display/svg.js b/src/display/svg.js index 56019e1e9..d61f184bf 100644 --- a/src/display/svg.js +++ b/src/display/svg.js @@ -1370,9 +1370,9 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { // The previous clipping group content can go out of order -- resetting // cached clipGroups. current.clipGroup = null; - this.extraStack.forEach(function (prev) { + for (const prev of this.extraStack) { prev.clipGroup = null; - }); + } // Intersect with the previous clipping path. clipPath.setAttributeNS(null, "clip-path", current.activeClipUrl); } diff --git a/src/display/text_layer.js b/src/display/text_layer.js index ab8abd2b2..6282cfe59 100644 --- a/src/display/text_layer.js +++ b/src/display/text_layer.js @@ -312,8 +312,8 @@ const renderTextLayer = (function renderTextLayerClosure() { // Finding intersections with expanded box. const points = [[0, 0], [0, b.size[1]], [b.size[0], 0], b.size]; const ts = new Float64Array(64); - points.forEach(function (p, j) { - const t = Util.applyTransform(p, m); + for (let j = 0, jj = points.length; j < jj; j++) { + const t = Util.applyTransform(points[j], m); ts[j + 0] = c && (e.left - t[0]) / c; ts[j + 4] = s && (e.top - t[1]) / s; ts[j + 8] = c && (e.right - t[0]) / c; @@ -333,7 +333,7 @@ const renderTextLayer = (function renderTextLayerClosure() { ts[j + 52] = c && (e.top - t[1]) / -c; ts[j + 56] = s && (e.right - t[0]) / s; ts[j + 60] = c && (e.bottom - t[1]) / -c; - }); + } // Not based on math, but to simplify calculations, using cos and sin // absolute values to not exceed the box (it can but insignificantly). const boxScale = 1 + Math.min(Math.abs(c), Math.abs(s)); @@ -358,8 +358,9 @@ const renderTextLayer = (function renderTextLayerClosure() { }; }); expandBoundsLTR(width, bounds); + const expanded = new Array(boxes.length); - bounds.forEach(function (b) { + for (const b of bounds) { const i = b.index; expanded[i] = { left: b.x1New, @@ -367,7 +368,7 @@ const renderTextLayer = (function renderTextLayerClosure() { right: b.x2New, bottom: 0, }; - }); + } // Rotating on 90 degrees and extending extended boxes. Reusing the bounds // array and objects. @@ -384,11 +385,11 @@ const renderTextLayer = (function renderTextLayerClosure() { }); expandBoundsLTR(height, bounds); - bounds.forEach(function (b) { + for (const b of bounds) { const i = b.index; expanded[i].top = b.x1New; expanded[i].bottom = b.x2New; - }); + } return expanded; } @@ -416,7 +417,7 @@ const renderTextLayer = (function renderTextLayerClosure() { }, ]; - bounds.forEach(function (boundary) { + for (const boundary of bounds) { // Searching for the affected part of horizon. // TODO red-black tree or simple binary search let i = 0; @@ -555,15 +556,15 @@ const renderTextLayer = (function renderTextLayerClosure() { horizon, [i, j - i + 1].concat(changedHorizon) ); - }); + } // Set new x2 for all unset boundaries. - horizon.forEach(function (horizonPart) { + for (const horizonPart of horizon) { const affectedBoundary = horizonPart.boundary; if (affectedBoundary.x2New === undefined) { affectedBoundary.x2New = Math.max(width, affectedBoundary.x2); } - }); + } } /** diff --git a/src/display/transport_stream.js b/src/display/transport_stream.js index d0d6044df..5659d496c 100644 --- a/src/display/transport_stream.js +++ b/src/display/transport_stream.js @@ -147,10 +147,9 @@ class PDFDataTransportStream { if (this._fullRequestReader) { this._fullRequestReader.cancel(reason); } - const readers = this._rangeReaders.slice(0); - readers.forEach(function (rangeReader) { - rangeReader.cancel(reason); - }); + for (const reader of this._rangeReaders.slice(0)) { + reader.cancel(reason); + } this._pdfDataRangeTransport.abort(); } } @@ -228,9 +227,9 @@ class PDFDataTransportStreamReader { cancel(reason) { this._done = true; - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } this._requests = []; } @@ -264,9 +263,9 @@ class PDFDataTransportStreamRangeReader { } else { const requestsCapability = this._requests.shift(); requestsCapability.resolve({ value: chunk, done: false }); - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } this._requests = []; } this._done = true; @@ -293,9 +292,9 @@ class PDFDataTransportStreamRangeReader { cancel(reason) { this._done = true; - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } this._requests = []; this._stream._removeRangeReader(this); } diff --git a/web/ui_utils.js b/web/ui_utils.js index 44a01b97b..d9af9235b 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -775,22 +775,22 @@ class EventBus { let externalListeners; // Making copy of the listeners array in case if it will be modified // during dispatch. - eventListeners.slice(0).forEach(({ listener, external, once }) => { + for (const { listener, external, once } of eventListeners.slice(0)) { if (once) { this._off(eventName, listener); } if (external) { (externalListeners ||= []).push(listener); - return; + continue; } listener.apply(null, args); - }); + } // Dispatch any "external" listeners *after* the internal ones, to give the // viewer components time to handle events and update their state first. if (externalListeners) { - externalListeners.forEach(listener => { + for (const listener of externalListeners) { listener.apply(null, args); - }); + } externalListeners = null; } if ( From 4078dd856c6108eb29b7774d28c5bbaee47e8b6c Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 24 Apr 2021 12:52:09 +0200 Subject: [PATCH 2/2] Clear some Arrays, rather than re-initialize them, in `src/display/`-code It's generally better to re-use the same Array, by clearing out all of its elements, rather than creating a new Array. --- src/display/network.js | 12 ++++++------ src/display/transport_stream.js | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/display/network.js b/src/display/network.js index e415a419b..a2f4642d1 100644 --- a/src/display/network.js +++ b/src/display/network.js @@ -350,7 +350,7 @@ class PDFNetworkStreamFullRequestReader { for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); } - this._requests = []; + this._requests.length = 0; } _onError(status) { @@ -361,8 +361,8 @@ class PDFNetworkStreamFullRequestReader { for (const requestCapability of this._requests) { requestCapability.reject(exception); } - this._requests = []; - this._cachedChunks = []; + this._requests.length = 0; + this._cachedChunks.length = 0; } _onProgress(data) { @@ -416,7 +416,7 @@ class PDFNetworkStreamFullRequestReader { for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); } - this._requests = []; + this._requests.length = 0; if (this._manager.isPendingRequest(this._fullRequestId)) { this._manager.abortRequest(this._fullRequestId); } @@ -459,7 +459,7 @@ class PDFNetworkStreamRangeRequestReader { for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); } - this._requests = []; + this._requests.length = 0; this._close(); } @@ -494,7 +494,7 @@ class PDFNetworkStreamRangeRequestReader { for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); } - this._requests = []; + this._requests.length = 0; if (this._manager.isPendingRequest(this._requestId)) { this._manager.abortRequest(this._requestId); } diff --git a/src/display/transport_stream.js b/src/display/transport_stream.js index 5659d496c..980cfa36a 100644 --- a/src/display/transport_stream.js +++ b/src/display/transport_stream.js @@ -230,7 +230,7 @@ class PDFDataTransportStreamReader { for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); } - this._requests = []; + this._requests.length = 0; } progressiveDone() { @@ -266,7 +266,7 @@ class PDFDataTransportStreamRangeReader { for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); } - this._requests = []; + this._requests.length = 0; } this._done = true; this._stream._removeRangeReader(this); @@ -295,7 +295,7 @@ class PDFDataTransportStreamRangeReader { for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); } - this._requests = []; + this._requests.length = 0; this._stream._removeRangeReader(this); } }