Delayed Execution

Add-ons using the techniques described in this document are considered a legacy technology in Firefox. Don't use these techniques to develop new add-ons. Use WebExtensions instead. If you maintain an add-on which uses the techniques described here, consider migrating it to use WebExtensions.

From Firefox 53 onwards, no new legacy add-ons will be accepted on addons.mozilla.org (AMO).

From Firefox 57 onwards, WebExtensions will be the only supported extension type, and Firefox will not load other types.

Even before Firefox 57, changes coming up in the Firefox platform will break many legacy extensions. These changes include multiprocess Firefox (e10s), sandboxing, and multiple content processes. Legacy extensions that are affected by these changes should migrate to WebExtensions if they can. See the "Compatibility Milestones" document for more.

A wiki page containing resources, migration paths, office hours, and more, is available to help developers transition to the new technologies.

Queuing a task in the main event loop

When a task needs to be only briefly delayed, such that it runs after the current call chain returns, it can be added directly to the main thread's event queue rather than scheduled as a timeout:

function executeSoon(func) {
  Services.tm.mainThread.dispatch(func, Ci.nsIThread.DISPATCH_NORMAL);
}

Using nsITimers to schedule tasks

In instances where setTimeout() and setInterval() are unavailable, or insufficient, tasks can be scheduled with delays using nsITimer instances.

Note: If an nsITimer is garbage collected, it will be deactivated and its callbacks will not fire. A reference to the timer objects must be explicitly kept alive until that point.

Some example usages include:

  const Timer = Components.Constructor("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
  function delay(timeout, func) {
    let timer = new Timer(function () {
      // Remove the reference so that it can be reaped.
      delete delay.timers[idx];
      func();
    }, timeout, Ci.nsITimer.TYPE_ONE_SHOT);
    // Store a reference to the timer so that it's not reaped before it fires.
    let idx = delay.timers.push(timer) - 1;
    return idx;
  }
  delay.timers = [];
  function repeat(timeout, func) {
    let timer = new Timer(function () {
      func();
    }, timeout, Ci.nsITimer.TYPE_REPEATING_SLACK);
    // Store a reference to the timer so that it's not reaped before it fires.
    let idx = delay.timers.push(timer) - 1;
    return idx;
  }
  repeat.timers = [];
  // Repeat a task every 1200ms
  repeat(1200, doAThing);
  // Do something 320ms from now
  delay(320, doSomething);

Document Tags and Contributors

Tags: 
 Last updated by: bunnybooboo,