addon-sdk/source/lib/sdk/timers.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/addon-sdk/source/lib/sdk/timers.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,105 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +'use strict';
     1.8 +
     1.9 +module.metadata = {
    1.10 +  "stability": "stable"
    1.11 +};
    1.12 +
    1.13 +const { CC, Cc, Ci } = require("chrome");
    1.14 +const { when: unload } = require("./system/unload");
    1.15 +
    1.16 +const { TYPE_ONE_SHOT, TYPE_REPEATING_SLACK } = Ci.nsITimer;
    1.17 +const Timer = CC("@mozilla.org/timer;1", "nsITimer");
    1.18 +const timers = Object.create(null);
    1.19 +const threadManager = Cc["@mozilla.org/thread-manager;1"].
    1.20 +                      getService(Ci.nsIThreadManager);
    1.21 +const prefBranch = Cc["@mozilla.org/preferences-service;1"].
    1.22 +                    getService(Ci.nsIPrefService).
    1.23 +                    QueryInterface(Ci.nsIPrefBranch);
    1.24 +
    1.25 +let MIN_DELAY = 4;
    1.26 +// Try to get min timeout delay used by browser.
    1.27 +try { MIN_DELAY = prefBranch.getIntPref("dom.min_timeout_value"); } finally {}
    1.28 +
    1.29 +
    1.30 +// Last timer id.
    1.31 +let lastID = 0;
    1.32 +
    1.33 +// Sets typer either by timeout or by interval
    1.34 +// depending on a given type.
    1.35 +function setTimer(type, callback, delay, ...args) {
    1.36 +  let id = ++ lastID;
    1.37 +  let timer = timers[id] = Timer();
    1.38 +  timer.initWithCallback({
    1.39 +    notify: function notify() {
    1.40 +      try {
    1.41 +        if (type === TYPE_ONE_SHOT)
    1.42 +          delete timers[id];
    1.43 +        callback.apply(null, args);
    1.44 +      }
    1.45 +      catch(error) {
    1.46 +        console.exception(error);
    1.47 +      }
    1.48 +    }
    1.49 +  }, Math.max(delay || MIN_DELAY), type);
    1.50 +  return id;
    1.51 +}
    1.52 +
    1.53 +function unsetTimer(id) {
    1.54 +  let timer = timers[id];
    1.55 +  delete timers[id];
    1.56 +  if (timer) timer.cancel();
    1.57 +}
    1.58 +
    1.59 +let immediates = new Map();
    1.60 +
    1.61 +let dispatcher = _ => {
    1.62 +  // Allow scheduling of a new dispatch loop.
    1.63 +  dispatcher.scheduled = false;
    1.64 +  // Take a snapshot of timer `id`'s that have being present before
    1.65 +  // starting a dispatch loop, in order to ignore timers registered
    1.66 +  // in side effect to dispatch while also skipping immediates that
    1.67 +  // were removed in side effect.
    1.68 +  let ids = [id for ([id] of immediates)];
    1.69 +  for (let id of ids) {
    1.70 +    let immediate = immediates.get(id);
    1.71 +    if (immediate) {
    1.72 +      immediates.delete(id);
    1.73 +      try { immediate(); }
    1.74 +      catch (error) { console.exception(error); }
    1.75 +    }
    1.76 +  }
    1.77 +}
    1.78 +
    1.79 +function setImmediate(callback, ...params) {
    1.80 +  let id = ++ lastID;
    1.81 +  // register new immediate timer with curried params.
    1.82 +  immediates.set(id, _ => callback.apply(callback, params));
    1.83 +  // if dispatch loop is not scheduled schedule one. Own scheduler
    1.84 +  if (!dispatcher.scheduled) {
    1.85 +    dispatcher.scheduled = true;
    1.86 +    threadManager.currentThread.dispatch(dispatcher,
    1.87 +                                         Ci.nsIThread.DISPATCH_NORMAL);
    1.88 +  }
    1.89 +  return id;
    1.90 +}
    1.91 +
    1.92 +function clearImmediate(id) {
    1.93 +  immediates.delete(id);
    1.94 +}
    1.95 +
    1.96 +// Bind timers so that toString-ing them looks same as on native timers.
    1.97 +exports.setImmediate = setImmediate.bind(null);
    1.98 +exports.clearImmediate = clearImmediate.bind(null);
    1.99 +exports.setTimeout = setTimer.bind(null, TYPE_ONE_SHOT);
   1.100 +exports.setInterval = setTimer.bind(null, TYPE_REPEATING_SLACK);
   1.101 +exports.clearTimeout = unsetTimer.bind(null);
   1.102 +exports.clearInterval = unsetTimer.bind(null);
   1.103 +
   1.104 +// all timers are cleared out on unload.
   1.105 +unload(function() {
   1.106 +  immediates.clear();
   1.107 +  Object.keys(timers).forEach(unsetTimer)
   1.108 +});

mercurial