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 +});