Bug 1381876 - Introduce TimedPromise. r=automatedtester

This introduces a specialisation of the well-known Promise that can
time out after a set limit, causing the promises' "reject" callback to
be invoked.

The TimedPromise object represents the timed, eventual completion
(or failure) of an asynchronous operation, and its resulting value.
In contrast to a regular Promise, it times out after a set timeframe.

MozReview-Commit-ID: Rb3POsPYeT

--HG--
extra : rebase_source : cdff792dfa43af3cff1b20b3e81edb1a826e561e
This commit is contained in:
Andreas Tolfsen 2017-08-01 18:28:13 +01:00
Родитель c956360dcb
Коммит e611d3c375
1 изменённых файлов: 64 добавлений и 4 удалений

Просмотреть файл

@ -6,9 +6,12 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("chrome://marionette/content/error.js");
const {
error,
TimeoutError,
} = Cu.import("chrome://marionette/content/error.js", {});
this.EXPORTED_SYMBOLS = ["wait"];
this.EXPORTED_SYMBOLS = ["wait", "TimedPromise"];
/**
* Poll-waiting utilities.
@ -17,6 +20,8 @@ this.EXPORTED_SYMBOLS = ["wait"];
*/
this.wait = {};
const {TYPE_ONE_SHOT, TYPE_REPEATING_SLACK} = Ci.nsITimer;
/**
* @callback Condition
*
@ -104,9 +109,8 @@ wait.until = function(func, timeout = 2000, interval = 10) {
// before invoking |evalFn|
evalFn();
timer.init(evalFn, interval, Ci.nsITimer.TYPE_REPEATING_SLACK);
timer.init(evalFn, interval, TYPE_REPEATING_SLACK);
// cancel timer and propagate result
}).then(res => {
timer.cancel();
return res;
@ -115,3 +119,59 @@ wait.until = function(func, timeout = 2000, interval = 10) {
throw err;
});
};
/**
* The <code>TimedPromise</code> object represents the timed, eventual
* completion (or failure) of an asynchronous operation, and its
* resulting value.
*
* In contrast to a regular {@link Promise}, it times out after
* <var>timeout</var>.
*
* @param {Condition} func
* Function to run, which will have its <code>reject</code>
* callback invoked after the <var>timeout</var> duration is reached.
* It is given two callbacks: <code>resolve(value)</code> and
* <code>reject(error)</code>.
* @param {timeout=} [timeout=1500] timeout
* <var>condition</var>'s <code>reject</code> callback will be called
* after this timeout.
* @param {Error=} [throws=TimeoutError] throws
* When the <var>timeout</var> is hit, this error class will be
* thrown. If it is null, no error is thrown and the promise is
* instead resolved on timeout.
*
* @return {Promise.<*>}
* Timed promise.
*/
function TimedPromise(fn, {timeout = 1500, throws = TimeoutError} = {}) {
const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
return new Promise((resolve, reject) => {
// Reject only if |throws| is given. Otherwise it is assumed that
// the user is OK with the promise timing out.
let bail = res => {
if (throws !== null) {
let err = new throws();
reject(err);
} else {
resolve();
}
};
timer.initWithCallback({notify: bail}, timeout, TYPE_ONE_SHOT);
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}).then(res => {
timer.cancel();
return res;
}, err => {
timer.cancel();
throw err;
});
}