Skip to content

Commit 4a03704

Browse files
authored
fix(async-utils): prevent timeout and interval checks in wait from leaving open handles (#682)
* fix(async-utils): prevent timeout and interval checks in wait from leaving open handles * refactor(async-utils): rename timeoutSignal to timeoutController
1 parent b869640 commit 4a03704

File tree

3 files changed

+50
-32
lines changed

3 files changed

+50
-32
lines changed

src/core/asyncUtils.ts

+11-22
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
AsyncUtils
88
} from '../types'
99

10-
import { resolveAfter, callAfter } from '../helpers/promises'
10+
import { createTimeoutController } from '../helpers/createTimeoutController'
1111
import { TimeoutError } from '../helpers/error'
1212

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

23+
const timeoutSignal = createTimeoutController(timeout)
24+
2325
const waitForResult = async () => {
2426
while (true) {
25-
await Promise.race(
26-
[
27-
new Promise<void>((resolve) => addResolver(resolve)),
28-
interval && resolveAfter(interval)
29-
].filter(Boolean)
30-
)
31-
32-
if (checkResult()) {
27+
const intervalSignal = createTimeoutController(interval)
28+
timeoutSignal.onTimeout(() => intervalSignal.cancel())
29+
30+
await intervalSignal.wrap(new Promise<void>(addResolver))
31+
32+
if (checkResult() || timeoutSignal.timedOut) {
3333
return
3434
}
3535
}
3636
}
3737

38-
let timedOut = false
39-
4038
if (!checkResult()) {
41-
if (timeout) {
42-
const timeoutPromise = () =>
43-
callAfter(() => {
44-
timedOut = true
45-
}, timeout)
46-
47-
await act(() => Promise.race([waitForResult(), timeoutPromise()]))
48-
} else {
49-
await act(waitForResult)
50-
}
39+
await act(() => timeoutSignal.wrap(waitForResult()))
5140
}
5241

53-
return !timedOut
42+
return !timeoutSignal.timedOut
5443
}
5544

5645
const waitFor = async (
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { WaitOptions } from '../types'
2+
3+
function createTimeoutController(timeout: WaitOptions['timeout']) {
4+
let timeoutId: NodeJS.Timeout
5+
const timeoutCallbacks: Array<() => void> = []
6+
7+
const timeoutController = {
8+
onTimeout(callback: () => void) {
9+
timeoutCallbacks.push(callback)
10+
},
11+
wrap(promise: Promise<void>) {
12+
return new Promise<void>((resolve, reject) => {
13+
timeoutController.timedOut = false
14+
timeoutController.onTimeout(resolve)
15+
16+
if (timeout) {
17+
timeoutId = setTimeout(() => {
18+
timeoutController.timedOut = true
19+
timeoutCallbacks.forEach((callback) => callback())
20+
resolve()
21+
}, timeout)
22+
}
23+
24+
promise
25+
.then(resolve)
26+
.catch(reject)
27+
.finally(() => timeoutController.cancel())
28+
})
29+
},
30+
cancel() {
31+
clearTimeout(timeoutId)
32+
},
33+
timedOut: false
34+
}
35+
36+
return timeoutController
37+
}
38+
39+
export { createTimeoutController }

src/helpers/promises.ts

-10
This file was deleted.

0 commit comments

Comments
 (0)