Files
Rob Wu 7da0fc6819 Bug 2016940 - Automatically cancel DeferredTask when window unloads r=mconley
The _startIdleDispatch uses `ChromeUtils.idleDispatch`, which may keep
the DeferredTask instance alive longer than necessary, which in turn
prevents the task callback and its closure from being garbage collected.

This has resulted in observed window leaks at the end of test runs. To
prevent this issue from happening, we automatically detect whether the
callback belongs to a window, and if so, tie the (idle) timers to that
window, so that the callbacks are immediately released when that window
unloads.

We also clear the callback reference when `finalize()` is called, so
that the task callback and its closure are not kept alive for longer
than necessary (upon unload), even if the window is still alive.

Differential Revision: https://phabricator.services.mozilla.com/D284782
2026-03-02 22:00:00 +00:00

59 lines
1.1 KiB
JavaScript

"use strict";
/* globals reportTestResult */ // Defined by test_DeferredTask_window.js
/* globals window */ // We are running in a document.
const { DeferredTask } = ChromeUtils.importESModule(
"resource://gre/modules/DeferredTask.sys.mjs"
);
const task1 = new DeferredTask(
() => {
reportTestResult("all_timeouts_zero");
},
0, // No timeout.
0 // No idle timeout.
);
const task2 = new DeferredTask(
() => {
reportTestResult("idle_timeout_only");
},
0, // No timeout.
1 // idle timeout with short deadline
);
const task3 = new DeferredTask(
() => {
reportTestResult("timer_only");
},
1, // Short timer.
0 // No idle timeout.
);
const task4 = new DeferredTask(
() => {
reportTestResult("all_timeouts_one");
},
1, // Short timer.
1 // Short idle timeout.
);
// Sanity check: verify that DeferredTask can run at least once.
new DeferredTask(
() => {
// Now arm the other timers...
task1.arm();
task2.arm();
task3.arm();
task4.arm();
reportTestResult("removing_iframe");
// Remove the iframe embedding this script.
window.frameElement.remove();
},
0,
0
).arm();