mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1145187 - Add a Poller utility object for togglign on polling functions. r=jryans
This commit is contained in:
parent
8343dadf03
commit
07fd15b012
@ -55,6 +55,7 @@ EXTRA_JS_MODULES.devtools.shared += [
|
||||
'node-attribute-parser.js',
|
||||
'observable-object.js',
|
||||
'options-view.js',
|
||||
'poller.js',
|
||||
'source-utils.js',
|
||||
'telemetry.js',
|
||||
'theme-switching.js',
|
||||
|
115
browser/devtools/shared/poller.js
Normal file
115
browser/devtools/shared/poller.js
Normal file
@ -0,0 +1,115 @@
|
||||
/* 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";
|
||||
loader.lazyRequireGetter(this, "timers",
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
loader.lazyRequireGetter(this, "defer",
|
||||
"sdk/core/promise", true);
|
||||
|
||||
/**
|
||||
* @constructor Poller
|
||||
* Takes a function that is to be called on an interval,
|
||||
* and can be turned on and off via methods to execute `fn` on the interval
|
||||
* specified during `on`. If `fn` returns a promise, the polling waits for
|
||||
* that promise to resolve before waiting the interval to call again.
|
||||
*
|
||||
* Specify the `wait` duration between polling here, and optionally
|
||||
* an `immediate` boolean, indicating whether the function should be called
|
||||
* immediately when toggling on.
|
||||
*
|
||||
* @param {function} fn
|
||||
* @param {number} wait
|
||||
* @param {boolean?} immediate
|
||||
*/
|
||||
function Poller (fn, wait, immediate) {
|
||||
this._fn = fn;
|
||||
this._wait = wait;
|
||||
this._immediate = immediate;
|
||||
this._poll = this._poll.bind(this);
|
||||
this._preparePoll = this._preparePoll.bind(this);
|
||||
}
|
||||
exports.Poller = Poller;
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether or not poller
|
||||
* is polling.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Poller.prototype.isPolling = function pollerIsPolling () {
|
||||
return !!this._timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Turns polling on.
|
||||
*
|
||||
* @return {Poller}
|
||||
*/
|
||||
Poller.prototype.on = function pollerOn () {
|
||||
if (this._destroyed) {
|
||||
throw Error("Poller cannot be turned on after destruction.");
|
||||
}
|
||||
if (this._timer) {
|
||||
this.off();
|
||||
}
|
||||
this._immediate ? this._poll() : this._preparePoll();
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Turns off polling. Returns a promise that resolves when
|
||||
* the last outstanding `fn` call finishes if it's an async function.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
Poller.prototype.off = function pollerOff () {
|
||||
let { resolve, promise } = defer();
|
||||
if (this._timer) {
|
||||
timers.clearTimeout(this._timer);
|
||||
this._timer = null;
|
||||
}
|
||||
|
||||
// Settle an inflight poll call before resolving
|
||||
// if using a promise-backed poll function
|
||||
if (this._inflight) {
|
||||
this._inflight.then(resolve);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
return promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Turns off polling and removes the reference to the poller function.
|
||||
* Resolves when the last outstanding `fn` call finishes if it's an async function.
|
||||
*/
|
||||
Poller.prototype.destroy = function pollerDestroy () {
|
||||
return this.off().then(() => {
|
||||
this._destroyed = true;
|
||||
this._fn = null
|
||||
});
|
||||
};
|
||||
|
||||
Poller.prototype._preparePoll = function pollerPrepare () {
|
||||
this._timer = timers.setTimeout(this._poll, this._wait);
|
||||
};
|
||||
|
||||
Poller.prototype._poll = function pollerPoll () {
|
||||
let response = this._fn();
|
||||
if (response && typeof response.then === "function") {
|
||||
// Store the most recent in-flight polling
|
||||
// call so we can clean it up when disabling
|
||||
this._inflight = response;
|
||||
response.then(() => {
|
||||
// Only queue up the next call if poller was not turned off
|
||||
// while this async poll call was in flight.
|
||||
if (this._timer) {
|
||||
this._preparePoll();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._preparePoll();
|
||||
}
|
||||
};
|
@ -84,6 +84,7 @@ skip-if = e10s # Layouthelpers test should not run in a content page.
|
||||
[browser_options-view-01.js]
|
||||
[browser_outputparser.js]
|
||||
skip-if = e10s # Test intermittently fails with e10s. Bug 1124162.
|
||||
[browser_poller.js]
|
||||
[browser_prefs-01.js]
|
||||
[browser_prefs-02.js]
|
||||
[browser_require_basic.js]
|
||||
|
131
browser/devtools/shared/test/browser_poller.js
Normal file
131
browser/devtools/shared/test/browser_poller.js
Normal file
@ -0,0 +1,131 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests the Poller class.
|
||||
|
||||
const { Poller } = devtools.require("devtools/shared/poller");
|
||||
|
||||
add_task(function* () {
|
||||
let count1 = 0, count2 = 0, count3 = 0;
|
||||
|
||||
let poller1 = new Poller(function () {
|
||||
count1++;
|
||||
}, 1000000000, true);
|
||||
let poller2 = new Poller(function () {
|
||||
count2++;
|
||||
}, 10);
|
||||
let poller3 = new Poller(function () {
|
||||
count3++;
|
||||
}, 1000000000);
|
||||
|
||||
poller2.on();
|
||||
|
||||
ok(!poller1.isPolling(), "isPolling() returns false for an off poller");
|
||||
ok(poller2.isPolling(), "isPolling() returns true for an on poller");
|
||||
|
||||
yield waitUntil(() => count2 > 10);
|
||||
|
||||
ok(count2 > 10, "poller that was turned on polled several times");
|
||||
ok(count1 === 0, "poller that was never turned on never polled");
|
||||
|
||||
yield poller2.off();
|
||||
let currentCount2 = count2;
|
||||
|
||||
poller1.on(); // Really high poll time!
|
||||
poller3.on(); // Really high poll time!
|
||||
|
||||
yield waitUntil(() => count1 === 1);
|
||||
ok(true, "Poller calls fn immediately when `immediate` is true");
|
||||
ok(count3 === 0, "Poller does not call fn immediately when `immediate` is not set");
|
||||
|
||||
ok(count2 === currentCount2, "a turned off poller does not continue to poll");
|
||||
yield poller2.off();
|
||||
yield poller2.off();
|
||||
yield poller2.off();
|
||||
ok(true, "Poller.prototype.off() is idempotent");
|
||||
|
||||
// This should still have not polled a second time
|
||||
is(count1, 1, "wait time works");
|
||||
|
||||
ok(poller1.isPolling(), "isPolling() returns true for an on poller");
|
||||
ok(!poller2.isPolling(), "isPolling() returns false for an off poller");
|
||||
});
|
||||
|
||||
add_task(function *() {
|
||||
let count = -1;
|
||||
// Create a poller that returns a promise.
|
||||
// The promise is resolved asynchronously after adding 9 to the count, ensuring
|
||||
// that on every poll, we have a multiple of 10.
|
||||
let asyncPoller = new Poller(function () {
|
||||
count++;
|
||||
ok(!(count%10), `Async poller called with a multiple of 10: ${count}`);
|
||||
return new Promise(function (resolve, reject) {
|
||||
let add9 = 9;
|
||||
let interval = setInterval(() => {
|
||||
if (add9--) {
|
||||
count++;
|
||||
} else {
|
||||
clearInterval(interval);
|
||||
resolve();
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
});
|
||||
|
||||
asyncPoller.on(1);
|
||||
yield waitUntil(() => count > 50);
|
||||
yield asyncPoller.off();
|
||||
});
|
||||
|
||||
add_task(function *() {
|
||||
// Create a poller that returns a promise. This poll call
|
||||
// is called immediately, and then subsequently turned off.
|
||||
// The call to `off` should not resolve until the inflight call
|
||||
// finishes.
|
||||
let inflightFinished = null;
|
||||
let pollCalls = 0;
|
||||
let asyncPoller = new Poller(function () {
|
||||
pollCalls++;
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(() => {
|
||||
inflightFinished = true;
|
||||
resolve();
|
||||
}, 1000);
|
||||
});
|
||||
}, 1, true);
|
||||
asyncPoller.on();
|
||||
|
||||
yield asyncPoller.off();
|
||||
ok(inflightFinished, "off() method does not resolve until remaining inflight poll calls finish");
|
||||
is(pollCalls, 1, "should only be one poll call to occur before turning off polling");
|
||||
});
|
||||
|
||||
add_task(function *() {
|
||||
// Create a poller that returns a promise. This poll call
|
||||
// is called immediately, and then subsequently turned off.
|
||||
// The call to `off` should not resolve until the inflight call
|
||||
// finishes.
|
||||
let inflightFinished = null;
|
||||
let pollCalls = 0;
|
||||
let asyncPoller = new Poller(function () {
|
||||
pollCalls++;
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(() => {
|
||||
inflightFinished = true;
|
||||
resolve();
|
||||
}, 1000);
|
||||
});
|
||||
}, 1, true);
|
||||
asyncPoller.on();
|
||||
|
||||
yield asyncPoller.destroy();
|
||||
ok(inflightFinished, "destroy() method does not resolve until remaining inflight poll calls finish");
|
||||
is(pollCalls, 1, "should only be one poll call to occur before destroying polling");
|
||||
|
||||
try {
|
||||
asyncPoller.on();
|
||||
ok(false, "Calling on() after destruction should throw");
|
||||
} catch (e) {
|
||||
ok(true, "Calling on() after destruction should throw");
|
||||
}
|
||||
});
|
@ -242,3 +242,24 @@ function* openAndCloseToolbox(nbOfTimes, usageTime, toolId) {
|
||||
yield gDevTools.closeToolbox(target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until a predicate returns true.
|
||||
*
|
||||
* @param function predicate
|
||||
* Invoked once in a while until it returns true.
|
||||
* @param number interval [optional]
|
||||
* How often the predicate is invoked, in milliseconds.
|
||||
*/
|
||||
function waitUntil(predicate, interval = 10) {
|
||||
if (predicate()) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
setTimeout(function() {
|
||||
waitUntil(predicate).then(() => resolve(true));
|
||||
}, interval);
|
||||
});
|
||||
}
|
||||
|
||||
// EventUtils just doesn't work!
|
||||
|
Loading…
Reference in New Issue
Block a user