diff --git a/services/web/frontend/js/features/pdf-preview/util/compiler.js b/services/web/frontend/js/features/pdf-preview/util/compiler.js index 0e69f60fa0..495d0ea8d1 100644 --- a/services/web/frontend/js/features/pdf-preview/util/compiler.js +++ b/services/web/frontend/js/features/pdf-preview/util/compiler.js @@ -5,6 +5,7 @@ import { debounce } from 'lodash' import { trackPdfDownload } from './metrics' import { enablePdfCaching } from './pdf-caching-flags' import { debugConsole } from '@/utils/debugging' +import { signalWithTimeout } from '@/utils/abort-signal' const AUTO_COMPILE_MAX_WAIT = 5000 // We add a 2 second debounce to sending user changes to server if they aren't @@ -86,17 +87,9 @@ export default class DocumentCompiler { } try { - if ( - typeof AbortSignal.any === 'function' && - typeof AbortSignal.timeout === 'function' - ) { - await this.openDocs.awaitBufferedOps( - AbortSignal.any([ - this.signal, - AbortSignal.timeout(PENDING_OP_MAX_WAIT), - ]) - ) - } + await this.openDocs.awaitBufferedOps( + signalWithTimeout(this.signal, PENDING_OP_MAX_WAIT) + ) // reset values this.setChangedAt(0) // TODO: wait for doc:saved? diff --git a/services/web/frontend/js/utils/abort-signal.ts b/services/web/frontend/js/utils/abort-signal.ts new file mode 100644 index 0000000000..98e9ce49ab --- /dev/null +++ b/services/web/frontend/js/utils/abort-signal.ts @@ -0,0 +1,25 @@ +export const supportsModernAbortSignal = + typeof AbortSignal.any === 'function' && + typeof AbortSignal.timeout === 'function' + +export const signalWithTimeout = (signal: AbortSignal, timeout: number) => { + if (supportsModernAbortSignal) { + return AbortSignal.any([signal, AbortSignal.timeout(timeout)]) + } + + const abortController = new AbortController() + + const abort = () => { + window.clearTimeout(timer) + signal.removeEventListener('abort', abort) + abortController.abort() + } + + // abort after timeout has expired + const timer = window.setTimeout(abort, timeout) + + // abort when the original signal is aborted + signal.addEventListener('abort', abort) + + return abortController.signal +}