Skip to content
This repository was archived by the owner on Dec 21, 2021. It is now read-only.

Commit 0ab73c8

Browse files
committed
refactor: Add cancellation memleak comments.
1 parent 246a245 commit 0ab73c8

File tree

1 file changed

+14
-6
lines changed

1 file changed

+14
-6
lines changed

src/utils/iterators.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,23 +204,31 @@ export function CancelableGenerator(iterable, onFinally = () => {}, { timeout =
204204

205205
try {
206206
yield* {
207-
// here is the meat:
208207
// each next() races against cancel signal
209208
next: async (...args) => {
210209
cancelSignal.removeAllListeners()
211-
const p = Defer()
210+
// NOTE:
211+
// Very easy to create a memleak here.
212+
// Using a shared promise with Promise.race
213+
// between loop iterations prevents data from being GC'ed.
214+
// Create new per-loop promise and resolve using an event emitter.
215+
const cancelPromise = Defer()
212216
const onCancel = (v) => {
213217
if (v instanceof Error) {
214-
p.reject(v)
218+
cancelPromise.reject(v)
215219
} else {
216-
p.resolve({ value: undefined, done: true })
220+
cancelPromise.resolve({ value: undefined, done: true })
217221
}
218222
}
219223

220224
cancelSignal.once('cancel', onCancel)
225+
const nextTask = iterator.next(...args)
226+
nextTask.finally(() => {
227+
cancelPromise.resolve()
228+
}).catch(() => {})
221229
return Promise.race([
222-
iterator.next(...args),
223-
p,
230+
nextTask,
231+
cancelPromise,
224232
])
225233
},
226234
async throw(err) {

0 commit comments

Comments
 (0)