mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Add polyfills for AbortSignal.any and AbortSignal.timeout (#24958)
GitOrigin-RevId: d0fc041054e17f50b5b19343e06e857bd9635902
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import '@/utils/abortsignal-polyfill'
|
||||
import * as PDFJS from 'pdfjs-dist'
|
||||
import type { DocumentInitParameters } from 'pdfjs-dist/types/src/display/api'
|
||||
|
||||
|
||||
@@ -1,25 +1,5 @@
|
||||
export const supportsModernAbortSignal =
|
||||
typeof AbortSignal.any === 'function' &&
|
||||
typeof AbortSignal.timeout === 'function'
|
||||
import './abortsignal-polyfill'
|
||||
|
||||
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
|
||||
return AbortSignal.any([signal, AbortSignal.timeout(timeout)])
|
||||
}
|
||||
|
||||
54
services/web/frontend/js/utils/abortsignal-polyfill.ts
Normal file
54
services/web/frontend/js/utils/abortsignal-polyfill.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
if (typeof AbortSignal.timeout !== 'function') {
|
||||
AbortSignal.timeout = (time: number) => {
|
||||
const controller = new AbortController()
|
||||
|
||||
function abort() {
|
||||
controller.abort(new DOMException('Timed out', 'TimeoutError'))
|
||||
}
|
||||
|
||||
function clean() {
|
||||
window.clearTimeout(timer)
|
||||
controller.signal.removeEventListener('abort', clean)
|
||||
}
|
||||
|
||||
controller.signal.addEventListener('abort', clean)
|
||||
|
||||
const timer = window.setTimeout(abort, time)
|
||||
|
||||
return controller.signal
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof AbortSignal.any !== 'function') {
|
||||
AbortSignal.any = (signals: AbortSignal[]) => {
|
||||
const controller = new AbortController()
|
||||
|
||||
// return immediately if any of the signals are already aborted.
|
||||
for (const signal of signals) {
|
||||
if (signal.aborted) {
|
||||
controller.abort(signal.reason)
|
||||
return controller.signal
|
||||
}
|
||||
}
|
||||
|
||||
function abort() {
|
||||
controller.abort()
|
||||
clean()
|
||||
}
|
||||
|
||||
function clean() {
|
||||
for (const signal of signals) {
|
||||
signal.removeEventListener('abort', abort)
|
||||
}
|
||||
}
|
||||
|
||||
// abort the controller (and clean up) when any of the signals aborts
|
||||
for (const signal of signals) {
|
||||
signal.addEventListener('abort', abort)
|
||||
}
|
||||
|
||||
return controller.signal
|
||||
}
|
||||
}
|
||||
|
||||
export default null // show that this is a module
|
||||
@@ -0,0 +1,43 @@
|
||||
describe('AbortSignal polyfills', function () {
|
||||
before(function () {
|
||||
// @ts-expect-error deleting a required method
|
||||
delete AbortSignal.any
|
||||
// @ts-expect-error deleting a required method
|
||||
delete AbortSignal.timeout
|
||||
// this polyfill provides the required methods
|
||||
cy.wrap(import('@/utils/abortsignal-polyfill'))
|
||||
})
|
||||
|
||||
describe('AbortSignal.any', function () {
|
||||
it('aborts the new signal immediately if one of the signals is aborted already', function () {
|
||||
const controller1 = new AbortController()
|
||||
const controller2 = new AbortController()
|
||||
|
||||
controller1.abort()
|
||||
const signal = AbortSignal.any([controller1.signal, controller2.signal])
|
||||
|
||||
cy.wrap(signal.aborted).should('be.true')
|
||||
})
|
||||
|
||||
it('aborts the new signal asynchronously if one of the signals is aborted later', function () {
|
||||
const controller1 = new AbortController()
|
||||
const controller2 = new AbortController()
|
||||
|
||||
const signal = AbortSignal.any([controller1.signal, controller2.signal])
|
||||
controller1.abort()
|
||||
|
||||
cy.wrap(signal.aborted).should('be.true')
|
||||
})
|
||||
})
|
||||
|
||||
describe('AbortSignal.timeout', function () {
|
||||
it('aborts the signal after the timeout', function () {
|
||||
cy.clock().then(clock => {
|
||||
const signal = AbortSignal.timeout(1000)
|
||||
cy.wrap(signal.aborted).should('be.false')
|
||||
clock.tick(1000)
|
||||
cy.wrap(signal.aborted).should('be.true')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user