Skip to content

Commit

Permalink
fix(async-utils): prevent timeout and interval checks in wait from le…
Browse files Browse the repository at this point in the history
…aving open handles (#682)

* fix(async-utils): prevent timeout and interval checks in wait from leaving open handles

* refactor(async-utils): rename timeoutSignal to timeoutController
  • Loading branch information
mpeyper committed Aug 31, 2021
1 parent b869640 commit 4a03704
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 32 deletions.
33 changes: 11 additions & 22 deletions src/core/asyncUtils.ts
Expand Up @@ -7,7 +7,7 @@ import {
AsyncUtils
} from '../types'

import { resolveAfter, callAfter } from '../helpers/promises'
import { createTimeoutController } from '../helpers/createTimeoutController'
import { TimeoutError } from '../helpers/error'

const DEFAULT_INTERVAL = 50
Expand All @@ -20,37 +20,26 @@ function asyncUtils(act: Act, addResolver: (callback: () => void) => void): Asyn
return callbackResult ?? callbackResult === undefined
}

const timeoutSignal = createTimeoutController(timeout)

const waitForResult = async () => {
while (true) {
await Promise.race(
[
new Promise<void>((resolve) => addResolver(resolve)),
interval && resolveAfter(interval)
].filter(Boolean)
)

if (checkResult()) {
const intervalSignal = createTimeoutController(interval)
timeoutSignal.onTimeout(() => intervalSignal.cancel())

await intervalSignal.wrap(new Promise<void>(addResolver))

if (checkResult() || timeoutSignal.timedOut) {
return
}
}
}

let timedOut = false

if (!checkResult()) {
if (timeout) {
const timeoutPromise = () =>
callAfter(() => {
timedOut = true
}, timeout)

await act(() => Promise.race([waitForResult(), timeoutPromise()]))
} else {
await act(waitForResult)
}
await act(() => timeoutSignal.wrap(waitForResult()))
}

return !timedOut
return !timeoutSignal.timedOut
}

const waitFor = async (
Expand Down
39 changes: 39 additions & 0 deletions src/helpers/createTimeoutController.ts
@@ -0,0 +1,39 @@
import { WaitOptions } from '../types'

function createTimeoutController(timeout: WaitOptions['timeout']) {
let timeoutId: NodeJS.Timeout
const timeoutCallbacks: Array<() => void> = []

const timeoutController = {
onTimeout(callback: () => void) {
timeoutCallbacks.push(callback)
},
wrap(promise: Promise<void>) {
return new Promise<void>((resolve, reject) => {
timeoutController.timedOut = false
timeoutController.onTimeout(resolve)

if (timeout) {
timeoutId = setTimeout(() => {
timeoutController.timedOut = true
timeoutCallbacks.forEach((callback) => callback())
resolve()
}, timeout)
}

promise
.then(resolve)
.catch(reject)
.finally(() => timeoutController.cancel())
})
},
cancel() {
clearTimeout(timeoutId)
},
timedOut: false
}

return timeoutController
}

export { createTimeoutController }
10 changes: 0 additions & 10 deletions src/helpers/promises.ts

This file was deleted.

0 comments on commit 4a03704

Please sign in to comment.