forked from mirrors/gecko-dev
		
	 2961eba0d6
			
		
	
	
		2961eba0d6
		
	
	
	
	
		
			
			Note that this value, 300, is still far above the 95% threshold that telemetry is reporting (59 milliseconds) so this won't be noticeable to most users. The > 1% of users who are having this issue will benefit greatly from this change. MozReview-Commit-ID: Bd51gjc5z83 --HG-- extra : rebase_source : 4a9e96eb555e8021012a3a06cb76e03413a8da20
		
			
				
	
	
		
			126 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 | |
|  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| "use strict";
 | |
| 
 | |
| var EXPORTED_SYMBOLS = ["SchedulePressure"];
 | |
| 
 | |
| ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 | |
| ChromeUtils.defineModuleGetter(this, "TelemetryStopwatch",
 | |
|   "resource://gre/modules/TelemetryStopwatch.jsm");
 | |
| XPCOMUtils.defineLazyPreferenceGetter(this, "SCHEDULE_PRESSURE_ENABLED",
 | |
|   "browser.schedulePressure.enabled", true);
 | |
| XPCOMUtils.defineLazyPreferenceGetter(this, "TIMEOUT_AMOUNT",
 | |
|   "browser.schedulePressure.timeoutMs", 300);
 | |
| 
 | |
| /**
 | |
|  * The SchedulePressure object provides the ability to alter
 | |
|  * the behavior of a program based on the idle activity of the
 | |
|  * host machine.
 | |
|  */
 | |
| var SchedulePressure = {
 | |
|   _idleCallbackWeakMap: new WeakMap(),
 | |
|   _setTimeoutWeakMap: new WeakMap(),
 | |
|   _telemetryCallbackWeakMap: new WeakMap(),
 | |
| 
 | |
|   _createTimeoutFn(window, callbackFn) {
 | |
|     return () => {
 | |
|       if (window.closed) {
 | |
|         TelemetryStopwatch.cancel("FX_SCHEDULE_PRESSURE_IDLE_SAMPLE_MS", window);
 | |
|         this._telemetryCallbackWeakMap.delete(window);
 | |
|         return;
 | |
|       }
 | |
|       let nextCallbackId = window.requestIdleCallback(callbackFn, {timeout: TIMEOUT_AMOUNT});
 | |
|       this._idleCallbackWeakMap.set(window, nextCallbackId);
 | |
| 
 | |
|       // Don't create another timeout-less idle callback if the first
 | |
|       // one hasn't completed yet.
 | |
|       if (!this._telemetryCallbackWeakMap.has(window) &&
 | |
|           TelemetryStopwatch.start("FX_SCHEDULE_PRESSURE_IDLE_SAMPLE_MS", window)) {
 | |
|         let telemetryCallbackId = window.requestIdleCallback(() => {
 | |
|           TelemetryStopwatch.finish("FX_SCHEDULE_PRESSURE_IDLE_SAMPLE_MS", window);
 | |
|           this._telemetryCallbackWeakMap.delete(window);
 | |
|         });
 | |
|         this._telemetryCallbackWeakMap.set(window, telemetryCallbackId);
 | |
|       }
 | |
|     };
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Starts an interval timeout that periodically waits for
 | |
|    * an idle callback. If the idle callback fails to get called
 | |
|    * within the timeout specified by TIMEOUT_AMOUNT, the
 | |
|    * highPressureFn callback will get called. Otherwise the
 | |
|    * lowPressureFn callback will get called.
 | |
|    *
 | |
|    * @param  window
 | |
|    *         The DOM window of the requestee.
 | |
|    * @param  options
 | |
|    *           highPressureFn
 | |
|    *           A function that will be called when the idle callback
 | |
|    *           fails to be called within the time specified by TIMEOUT_AMOUNT.
 | |
|    *           Returning an object with property of `continueMonitoring` set
 | |
|    *           to `false` will prevent further monitoring.
 | |
|    *           lowPressureFn
 | |
|    *           A function that will be called when the idle callback
 | |
|    *           gets called within the time specified by TIMEOUT_AMOUNT.
 | |
|    *           Returning an object with property of `continueMonitoring` set
 | |
|    *           to `false` will prevent further monitoring.
 | |
|    */
 | |
|   startMonitoring(window, {highPressureFn, lowPressureFn}) {
 | |
|     if (!SCHEDULE_PRESSURE_ENABLED ||
 | |
|         this._setTimeoutWeakMap.has(window) ||
 | |
|         this._idleCallbackWeakMap.has(window)) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let callbackFn = idleDeadline => {
 | |
|       if (window.closed) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       let result;
 | |
|       if (idleDeadline.didTimeout) {
 | |
|         try {
 | |
|           result = highPressureFn();
 | |
|         } catch (ex) {}
 | |
|       } else {
 | |
|         try {
 | |
|           result = lowPressureFn();
 | |
|         } catch (ex) {}
 | |
|       }
 | |
| 
 | |
|       if (result && !result.continueMonitoring) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       this._setTimeoutWeakMap.set(window,
 | |
|         window.setTimeout(this._createTimeoutFn(window, callbackFn), TIMEOUT_AMOUNT));
 | |
|     };
 | |
| 
 | |
|     this._setTimeoutWeakMap.set(window,
 | |
|       window.setTimeout(this._createTimeoutFn(window, callbackFn), TIMEOUT_AMOUNT));
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Stops the interval timeout that periodically waits for
 | |
|    * an idle callback.
 | |
|    *
 | |
|    * @param  window
 | |
|    *         The DOM window of the requestee.
 | |
|    */
 | |
|   stopMonitoring(window) {
 | |
|     function removeFromMapAndCancelTimeout(map, cancelFn) {
 | |
|       if (map.has(window)) {
 | |
|         cancelFn(map.get(window));
 | |
|         map.delete(window);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     TelemetryStopwatch.cancel("FX_SCHEDULE_PRESSURE_IDLE_SAMPLE_MS", window);
 | |
|     removeFromMapAndCancelTimeout(this._setTimeoutWeakMap, window.clearTimeout);
 | |
|     removeFromMapAndCancelTimeout(this._idleCallbackWeakMap, window.cancelIdleCallback);
 | |
|     removeFromMapAndCancelTimeout(this._telemetryCallbackWeakMap, window.cancelIdleCallback);
 | |
|   },
 | |
| };
 |