aboutsummaryrefslogtreecommitdiff
path: root/node_modules/selenium-webdriver/lib/promise.js
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-04-20 03:09:25 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-04-24 16:14:29 +0200
commit82f2b76e25a4a67e01ec67e5ebe39d14ad771ea8 (patch)
tree965f6eb89b84d65a62b49008fd972c004832ccd1 /node_modules/selenium-webdriver/lib/promise.js
parente6e0cbc387c2a77b48e4065c229daa65bf1aa0fa (diff)
Reorganize module loading.
We now use webpack instead of SystemJS, effectively bundling modules into one file (plus commons chunks) for every entry point. This results in a much smaller extension size (almost half). Furthermore we use yarn/npm even for extension run-time dependencies. This relieves us from manually vendoring and building dependencies. It's also easier to understand for new developers familiar with node.
Diffstat (limited to 'node_modules/selenium-webdriver/lib/promise.js')
-rw-r--r--node_modules/selenium-webdriver/lib/promise.js286
1 files changed, 205 insertions, 81 deletions
diff --git a/node_modules/selenium-webdriver/lib/promise.js b/node_modules/selenium-webdriver/lib/promise.js
index 32d0c98e6..b26cd23ff 100644
--- a/node_modules/selenium-webdriver/lib/promise.js
+++ b/node_modules/selenium-webdriver/lib/promise.js
@@ -48,7 +48,7 @@
* > e => console.error('FAILURE: ' + e));
* > ```
* >
- * > The motiviation behind this change and full deprecation plan are documented
+ * > The motivation behind this change and full deprecation plan are documented
* > in [issue 2969](https://github.com/SeleniumHQ/selenium/issues/2969).
* >
* >
@@ -87,8 +87,7 @@
* The control flow is based on the concept of tasks and task queues. Tasks are
* functions that define the basic unit of work for the control flow to execute.
* Each task is scheduled via {@link ControlFlow#execute()}, which will return
- * a {@link ManagedPromise ManagedPromise} that will be resolved with the task's
- * result.
+ * a {@link ManagedPromise} that will be resolved with the task's result.
*
* A task queue contains all of the tasks scheduled within a single turn of the
* [JavaScript event loop][JSEL]. The control flow will create a new task queue
@@ -103,13 +102,13 @@
*
* Whenever the control flow creates a new task queue, it will automatically
* begin executing tasks in the next available turn of the event loop. This
- * execution is scheduled using a "micro-task" timer, such as a (native)
- * `ManagedPromise.then()` callback.
+ * execution is [scheduled as a microtask][MicrotasksArticle] like e.g. a
+ * (native) `Promise.then()` callback.
*
* setTimeout(() => console.log('a'));
- * ManagedPromise.resolve().then(() => console.log('b')); // A native promise.
+ * Promise.resolve().then(() => console.log('b')); // A native promise.
* flow.execute(() => console.log('c'));
- * ManagedPromise.resolve().then(() => console.log('d'));
+ * Promise.resolve().then(() => console.log('d'));
* setTimeout(() => console.log('fin'));
* // b
* // c
@@ -118,13 +117,13 @@
* // fin
*
* In the example above, b/c/d is logged before a/fin because native promises
- * and this module use "micro-task" timers, which have a higher priority than
- * "macro-tasks" like `setTimeout`.
+ * and this module use "microtask" timers, which have a higher priority than
+ * "macrotasks" like `setTimeout`.
*
* ## Task Execution
*
- * Upon creating a task queue, and whenever an exisiting queue completes a task,
- * the control flow will schedule a micro-task timer to process any scheduled
+ * Upon creating a task queue, and whenever an existing queue completes a task,
+ * the control flow will schedule a microtask timer to process any scheduled
* tasks. This ensures no task is ever started within the same turn of the
* JavaScript event loop in which it was scheduled, nor is a task ever started
* within the same turn that another finishes.
@@ -140,13 +139,13 @@
* discarded and the task's promised result (previously returned by
* {@link ControlFlow#execute()}) is immediately rejected with the thrown
* error.
- * 3. The task function returns sucessfully.
+ * 3. The task function returns successfully.
*
* If a task function created a new task queue, the control flow will wait for
* that queue to complete before processing the task result. If the queue
* completes without error, the flow will settle the task's promise with the
- * value originaly returned by the task function. On the other hand, if the task
- * queue termintes with an error, the task's promise will be rejected with that
+ * value originally returned by the task function. On the other hand, if the task
+ * queue terminates with an error, the task's promise will be rejected with that
* error.
*
* flow.execute(function() {
@@ -161,7 +160,7 @@
* ## ManagedPromise Integration
*
* In addition to the {@link ControlFlow} class, the promise module also exports
- * a [ManagedPromise/A+] {@linkplain ManagedPromise implementation} that is deeply
+ * a [Promises/A+] {@linkplain ManagedPromise implementation} that is deeply
* integrated with the ControlFlow. First and foremost, each promise
* {@linkplain ManagedPromise#then() callback} is scheduled with the
* control flow as a task. As a result, each callback is invoked in its own turn
@@ -328,7 +327,7 @@
* Even though a subtask's promised result will never resolve while the task
* function is on the stack, it will be treated as a promise resolved within the
* task. In all other scenarios, a task's promise behaves just like a normal
- * promise. In the sample below, `C/D` is loggged before `B` because the
+ * promise. In the sample below, `C/D` is logged before `B` because the
* resolution of `subtask1` interrupts the flow of the enclosing task. Within
* the final subtask, `E/F` is logged in order because `subtask1` is a resolved
* promise when that task runs.
@@ -467,17 +466,17 @@
*
* ES6 promises do not require users to handle a promise rejections. This can
* result in subtle bugs as the rejections are silently "swallowed" by the
- * ManagedPromise class.
+ * Promise class.
*
- * ManagedPromise.reject(Error('boom'));
+ * Promise.reject(Error('boom'));
* // ... *crickets* ...
*
* Selenium's promise module, on the other hand, requires that every rejection
* be explicitly handled. When a {@linkplain ManagedPromise ManagedPromise} is
* rejected and no callbacks are defined on that promise, it is considered an
- * _unhandled rejection_ and reproted to the active task queue. If the rejection
+ * _unhandled rejection_ and reported to the active task queue. If the rejection
* remains unhandled after a single turn of the [event loop][JSEL] (scheduled
- * with a micro-task), it will propagate up the stack.
+ * with a microtask), it will propagate up the stack.
*
* ## Error Propagation
*
@@ -534,7 +533,7 @@
*
* When a subtask is discarded due to an unreported rejection in its parent
* frame, the existing callbacks on that task will never settle and the
- * callbacks will not be invoked. If a new callback is attached ot the subtask
+ * callbacks will not be invoked. If a new callback is attached to the subtask
* _after_ it has been discarded, it is handled the same as adding a callback
* to a cancelled promise: the error-callback path is invoked. This behavior is
* intended to handle cases where the user saves a reference to a task promise,
@@ -582,9 +581,9 @@
*
* Bottom line: you __*must*__ handle rejected promises.
*
- * # ManagedPromise/A+ Compatibility
+ * # Promises/A+ Compatibility
*
- * This `promise` module is compliant with the [ManagedPromise/A+][] specification
+ * This `promise` module is compliant with the [Promises/A+] specification
* except for sections `2.2.6.1` and `2.2.6.2`:
*
* >
@@ -595,10 +594,10 @@
* > must execute in the order of their originating calls to `then`.
* >
*
- * Specifically, the conformance tests contains the following scenario (for
+ * Specifically, the conformance tests contain the following scenario (for
* brevity, only the fulfillment version is shown):
*
- * var p1 = ManagedPromise.resolve();
+ * var p1 = Promise.resolve();
* p1.then(function() {
* console.log('A');
* p1.then(() => console.log('B'));
@@ -609,7 +608,7 @@
* // B
*
* Since the [ControlFlow](#scheduling_callbacks) executes promise callbacks as
- * tasks, with this module, the result would be
+ * tasks, with this module, the result would be:
*
* var p2 = promise.fulfilled();
* p2.then(function() {
@@ -623,7 +622,8 @@
*
* [JSEL]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
* [GF]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
- * [ManagedPromise/A+]: https://promisesaplus.com/
+ * [Promises/A+]: https://promisesaplus.com/
+ * [MicrotasksArticle]: https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
*/
'use strict';
@@ -667,7 +667,7 @@ function getUid(obj) {
/**
- * Runs the given function after a micro-task yield.
+ * Runs the given function after a microtask yield.
* @param {function()} fn The function to run.
*/
function asyncRun(fn) {
@@ -942,7 +942,7 @@ class Thenable {
/**
* Marker interface for objects that allow consumers to request the cancellation
- * of a promies-based operation. A cancelled promise will be rejected with a
+ * of a promise-based operation. A cancelled promise will be rejected with a
* {@link CancellationError}.
*
* This interface is considered package-private and should not be used outside
@@ -1003,6 +1003,9 @@ const PromiseState = {
*/
const ON_CANCEL_HANDLER = new WeakMap;
+const SKIP_LOG = Symbol('skip-log');
+const FLOW_LOG = logging.getLogger('promise.ControlFlow');
+
/**
* Represents the eventual value of a completed operation. Each promise may be
@@ -1025,14 +1028,29 @@ class ManagedPromise {
* functions, one for fulfilling the promise and another for rejecting it.
* @param {ControlFlow=} opt_flow The control flow
* this instance was created under. Defaults to the currently active flow.
+ * @param {?=} opt_skipLog An internal parameter used to skip logging the
+ * creation of this promise. This parameter has no effect unless it is
+ * strictly equal to an internal symbol. In other words, this parameter
+ * is always ignored for external code.
*/
- constructor(resolver, opt_flow) {
+ constructor(resolver, opt_flow, opt_skipLog) {
if (!usePromiseManager()) {
throw TypeError(
'Unable to create a managed promise instance: the promise manager has'
+ ' been disabled by the SELENIUM_PROMISE_MANAGER environment'
+ ' variable: ' + process.env['SELENIUM_PROMISE_MANAGER']);
+ } else if (opt_skipLog !== SKIP_LOG) {
+ FLOW_LOG.warning(() => {
+ let e =
+ captureStackTrace(
+ 'ManagedPromiseError',
+ 'Creating a new managed Promise. This call will fail when the'
+ + ' promise manager is disabled',
+ ManagedPromise)
+ return e.stack;
+ });
}
+
getUid(this);
/** @private {!ControlFlow} */
@@ -1308,7 +1326,7 @@ class ManagedPromise {
* @param {!Function} fn The function to use as the top of the stack when
* recording the callback's creation point.
* @return {!ManagedPromise<R>} A new promise which will be resolved with the
- * esult of the invoked callback.
+ * result of the invoked callback.
* @template R
* @private
*/
@@ -1384,6 +1402,37 @@ function isPending(promise) {
/**
+ * Structural interface for a deferred promise resolver.
+ * @record
+ * @template T
+ */
+function Resolver() {}
+
+
+/**
+ * The promised value for this resolver.
+ * @type {!Thenable<T>}
+ */
+Resolver.prototype.promise;
+
+
+/**
+ * Resolves the promised value with the given `value`.
+ * @param {T|Thenable<T>} value
+ * @return {void}
+ */
+Resolver.prototype.resolve;
+
+
+/**
+ * Rejects the promised value with the given `reason`.
+ * @param {*} reason
+ * @return {void}
+ */
+Resolver.prototype.reject;
+
+
+/**
* Represents a value that will be resolved at some point in the future. This
* class represents the protected "producer" half of a ManagedPromise - each Deferred
* has a {@code promise} property that may be returned to consumers for
@@ -1395,20 +1444,25 @@ function isPending(promise) {
* {@link ControlFlow} as an unhandled failure.
*
* @template T
+ * @implements {Resolver<T>}
*/
class Deferred {
/**
* @param {ControlFlow=} opt_flow The control flow this instance was
* created under. This should only be provided during unit tests.
+ * @param {?=} opt_skipLog An internal parameter used to skip logging the
+ * creation of this promise. This parameter has no effect unless it is
+ * strictly equal to an internal symbol. In other words, this parameter
+ * is always ignored for external code.
*/
- constructor(opt_flow) {
+ constructor(opt_flow, opt_skipLog) {
var fulfill, reject;
/** @type {!ManagedPromise<T>} */
this.promise = new ManagedPromise(function(f, r) {
fulfill = f;
reject = r;
- }, opt_flow);
+ }, opt_flow, opt_skipLog);
var self = this;
var checkNotSelf = function(value) {
@@ -1421,16 +1475,24 @@ class Deferred {
* Resolves this deferred with the given value. It is safe to call this as a
* normal function (with no bound "this").
* @param {(T|IThenable<T>|Thenable)=} opt_value The fulfilled value.
+ * @const
*/
- this.fulfill = function(opt_value) {
+ this.resolve = function(opt_value) {
checkNotSelf(opt_value);
fulfill(opt_value);
};
/**
+ * An alias for {@link #resolve}.
+ * @const
+ */
+ this.fulfill = this.resolve;
+
+ /**
* Rejects this promise with the given reason. It is safe to call this as a
* normal function (with no bound "this").
* @param {*=} opt_reason The rejection reason.
+ * @const
*/
this.reject = function(opt_reason) {
checkNotSelf(opt_reason);
@@ -1487,36 +1549,76 @@ function delayed(ms) {
/**
- * Creates a new deferred object.
- * @return {!Deferred<T>} The new deferred object.
+ * Creates a new deferred resolver.
+ *
+ * If the promise manager is currently enabled, this function will return a
+ * {@link Deferred} instance. Otherwise, it will return a resolver for a
+ * {@linkplain NativePromise native promise}.
+ *
+ * @return {!Resolver<T>} A new deferred resolver.
* @template T
*/
function defer() {
- return new Deferred();
+ if (usePromiseManager()) {
+ return new Deferred();
+ }
+ let resolve, reject;
+ let promise = new NativePromise((_resolve, _reject) => {
+ resolve = _resolve;
+ reject = _reject;
+ });
+ return {promise, resolve, reject};
}
/**
* Creates a promise that has been resolved with the given value.
+ *
+ * If the promise manager is currently enabled, this function will return a
+ * {@linkplain ManagedPromise managed promise}. Otherwise, it will return a
+ * {@linkplain NativePromise native promise}.
+ *
* @param {T=} opt_value The resolved value.
- * @return {!ManagedPromise<T>} The resolved promise.
- * @deprecated Use {@link ManagedPromise#resolve Promise.resolve(value)}.
+ * @return {!Thenable<T>} The resolved promise.
* @template T
*/
function fulfilled(opt_value) {
- return ManagedPromise.resolve(opt_value);
+ let ctor = usePromiseManager() ? ManagedPromise : NativePromise;
+ if (opt_value instanceof ctor) {
+ return /** @type {!Thenable} */(opt_value);
+ }
+
+ if (usePromiseManager()) {
+ // We can skip logging warnings about creating a managed promise because
+ // this function will automatically switch to use a native promise when
+ // the promise manager is disabled.
+ return new ManagedPromise(
+ resolve => resolve(opt_value), undefined, SKIP_LOG);
+ }
+ return NativePromise.resolve(opt_value);
}
/**
* Creates a promise that has been rejected with the given reason.
+ *
+ * If the promise manager is currently enabled, this function will return a
+ * {@linkplain ManagedPromise managed promise}. Otherwise, it will return a
+ * {@linkplain NativePromise native promise}.
+ *
* @param {*=} opt_reason The rejection reason; may be any value, but is
* usually an Error or a string.
- * @return {!ManagedPromise<?>} The rejected promise.
- * @deprecated Use {@link ManagedPromise#reject Promise.reject(reason)}.
+ * @return {!Thenable<?>} The rejected promise.
*/
function rejected(opt_reason) {
- return ManagedPromise.reject(opt_reason);
+ if (usePromiseManager()) {
+ // We can skip logging warnings about creating a managed promise because
+ // this function will automatically switch to use a native promise when
+ // the promise manager is disabled.
+ return new ManagedPromise(
+ (_, reject) => reject(opt_reason), undefined, SKIP_LOG);
+ }
+ return NativePromise.reject(opt_reason);
}
@@ -1610,21 +1712,17 @@ function thenFinally(promise, callback) {
* @param {Function=} opt_errback The function to call when the value is
* rejected.
* @return {!Thenable} A new promise.
+ * @deprecated Use `promise.fulfilled(value).then(opt_callback, opt_errback)`
*/
function when(value, opt_callback, opt_errback) {
- if (Thenable.isImplementation(value)) {
- return value.then(opt_callback, opt_errback);
- }
-
- return createPromise(resolve => resolve(value))
- .then(opt_callback, opt_errback);
+ return fulfilled(value).then(opt_callback, opt_errback);
}
/**
* Invokes the appropriate callback function as soon as a promised `value` is
- * resolved. This function is similar to `when()`, except it does not return
- * a new promise.
+ * resolved.
+ *
* @param {*} value The value to observe.
* @param {Function} callback The function to call when the value is
* resolved successfully.
@@ -1826,7 +1924,7 @@ function filter(arr, fn, opt_self) {
*/
function fullyResolved(value) {
if (isPromise(value)) {
- return when(value, fullyResolveValue);
+ return fulfilled(value).then(fullyResolveValue);
}
return fullyResolveValue(value);
}
@@ -1973,7 +2071,7 @@ class Scheduler {
/**
* Schedules a task to wait for a condition to hold.
*
- * If the condition is defined as a function, it may return any value. Promies
+ * If the condition is defined as a function, it may return any value. Promise
* will be resolved before testing if the condition holds (resolution time
* counts towards the timeout). Once resolved, values are always evaluated as
* booleans.
@@ -1997,7 +2095,7 @@ class Scheduler {
* @param {string=} opt_message An optional error message to include if the
* wait times out; defaults to the empty string.
* @return {!Thenable<T>} A promise that will be fulfilled
- * when the condition has been satisified. The promise shall be rejected
+ * when the condition has been satisfied. The promise shall be rejected
* if the wait times out waiting for the condition.
* @throws {TypeError} If condition is not a function or promise or if timeout
* is not a number >= 0.
@@ -2018,6 +2116,10 @@ function usePromiseManager() {
/**
+ * Creates a new promise with the given `resolver` function. If the promise
+ * manager is currently enabled, the returned promise will be a
+ * {@linkplain ManagedPromise} instance. Otherwise, it will be a native promise.
+ *
* @param {function(
* function((T|IThenable<T>|Thenable|null)=),
* function(*=))} resolver
@@ -2040,7 +2142,7 @@ function createPromise(resolver) {
* @param {string=} opt_message An optional error message to include if the
* wait times out; defaults to the empty string.
* @return {!Thenable<T>} A promise that will be fulfilled
- * when the condition has been satisified. The promise shall be rejected
+ * when the condition has been satisfied. The promise shall be rejected
* if the wait times out waiting for the condition.
* @throws {TypeError} If condition is not a function or promise or if timeout
* is not a number >= 0.
@@ -2164,7 +2266,7 @@ const SIMPLE_SCHEDULER = new SimpleScheduler;
/**
* Handles the execution of scheduled tasks, each of which may be an
* asynchronous operation. The control flow will ensure tasks are executed in
- * the ordered scheduled, starting each task only once those before it have
+ * the order scheduled, starting each task only once those before it have
* completed.
*
* Each task scheduled within this flow may return a {@link ManagedPromise} to
@@ -2172,21 +2274,21 @@ const SIMPLE_SCHEDULER = new SimpleScheduler;
* promises to be resolved before marking the task as completed.
*
* Tasks and each callback registered on a {@link ManagedPromise} will be run
- * in their own ControlFlow frame. Any tasks scheduled within a frame will take
+ * in their own ControlFlow frame. Any tasks scheduled within a frame will take
* priority over previously scheduled tasks. Furthermore, if any of the tasks in
* the frame fail, the remainder of the tasks in that frame will be discarded
* and the failure will be propagated to the user through the callback/task's
* promised result.
*
* Each time a ControlFlow empties its task queue, it will fire an
- * {@link ControlFlow.EventType.IDLE IDLE} event. Conversely,
- * whenever the flow terminates due to an unhandled error, it will remove all
+ * {@link ControlFlow.EventType.IDLE IDLE} event. Conversely, whenever
+ * the flow terminates due to an unhandled error, it will remove all
* remaining tasks in its queue and fire an
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION UNCAUGHT_EXCEPTION} event.
* If there are no listeners registered with the flow, the error will be
* rethrown to the global error handler.
*
- * Refer to the {@link ./promise} module documentation for a detailed
+ * Refer to the {@link ./promise} module documentation for a detailed
* explanation of how the ControlFlow coordinates task execution.
*
* @implements {Scheduler}
@@ -2212,7 +2314,7 @@ class ControlFlow extends events.EventEmitter {
this.taskQueues_ = null;
/**
- * Micro task that controls shutting down the control flow. Upon shut down,
+ * Microtask that controls shutting down the control flow. Upon shut down,
* the flow will emit an
* {@link ControlFlow.EventType.IDLE} event. Idle events
* always follow a brief timeout in order to catch latent errors from the
@@ -2221,8 +2323,8 @@ class ControlFlow extends events.EventEmitter {
* by the promise system until the next turn of the event loop:
*
* // Schedule 1 task that fails.
- * var result = promise.controlFlow().schedule('example',
- * function() { return promise.rejected('failed'); });
+ * var result = promise.controlFlow().execute(
+ * () => promise.rejected('failed'), 'example');
* // Set a callback on the result. This delays reporting the unhandled
* // failure for 1 turn of the event loop.
* result.then(function() {});
@@ -2246,7 +2348,7 @@ class ControlFlow extends events.EventEmitter {
/**
* Returns a string representation of this control flow, which is its current
* {@linkplain #getSchedule() schedule}, sans task stack traces.
- * @return {string} The string representation of this contorl flow.
+ * @return {string} The string representation of this control flow.
* @override
*/
toString() {
@@ -2258,8 +2360,7 @@ class ControlFlow extends events.EventEmitter {
* control flow stack and cause rejections within parent tasks. If error
* propagation is disabled, tasks will not be aborted when an unhandled
* promise rejection is detected, but the rejection _will_ trigger an
- * {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION}
- * event.
+ * {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION} event.
*
* The default behavior is to propagate all unhandled rejections. _The use
* of this option is highly discouraged._
@@ -2293,7 +2394,7 @@ class ControlFlow extends events.EventEmitter {
* {@code opt_includeStackTraces === true}, the string will include the
* stack trace from when each task was scheduled.
* @param {string=} opt_includeStackTraces Whether to include the stack traces
- * from when each task was scheduled. Defaults to false.
+ * from when each task was scheduled. Defaults to false.
* @return {string} String representation of this flow's internal state.
*/
getSchedule(opt_includeStackTraces) {
@@ -2345,7 +2446,7 @@ class ControlFlow extends events.EventEmitter {
}
/**
- * Returns the currently actively task queue for this flow. If there is no
+ * Returns the currently active task queue for this flow. If there is no
* active queue, one will be created.
* @return {!TaskQueue} the currently active task queue for this flow.
* @private
@@ -2377,15 +2478,31 @@ class ControlFlow extends events.EventEmitter {
}
if (!this.hold_) {
- var holdIntervalMs = 2147483647; // 2^31-1; max timer length for Node.js
+ let holdIntervalMs = 2147483647; // 2^31-1; max timer length for Node.js
this.hold_ = setInterval(function() {}, holdIntervalMs);
}
- var task = new Task(
+ let task = new Task(
this, fn, opt_description || '<anonymous>',
- {name: 'Task', top: ControlFlow.prototype.execute});
+ {name: 'Task', top: ControlFlow.prototype.execute},
+ true);
+
+ let q = this.getActiveQueue_();
+
+ for (let i = q.tasks_.length; i > 0; i--) {
+ let previousTask = q.tasks_[i - 1];
+ if (previousTask.userTask_) {
+ FLOW_LOG.warning(() => {
+ return `Detected scheduling of an unchained task.
+When the promise manager is disabled, unchained tasks will not wait for
+previously scheduled tasks to finish before starting to execute.
+New task: ${task.promise.stack_.stack}
+Previous task: ${previousTask.promise.stack_.stack}`.split(/\n/).join('\n ');
+ });
+ break;
+ }
+ }
- var q = this.getActiveQueue_();
q.enqueue(task);
this.emit(ControlFlow.EventType.SCHEDULE_TASK, task.description);
return task.promise;
@@ -2393,7 +2510,7 @@ class ControlFlow extends events.EventEmitter {
/** @override */
promise(resolver) {
- return new ManagedPromise(resolver, this);
+ return new ManagedPromise(resolver, this, SKIP_LOG);
}
/** @override */
@@ -2622,7 +2739,7 @@ class MicroTask {
}
/**
- * Runs the given function after a micro-task yield.
+ * Runs the given function after a microtask yield.
* @param {function()} fn The function to run.
*/
static run(fn) {
@@ -2662,9 +2779,11 @@ class Task extends Deferred {
* @param {string} description A description of the task for debugging.
* @param {{name: string, top: !Function}=} opt_stackOptions Options to use
* when capturing the stacktrace for when this task was created.
+ * @param {boolean=} opt_isUserTask Whether this task was explicitly scheduled
+ * by the use of the promise manager.
*/
- constructor(flow, fn, description, opt_stackOptions) {
- super(flow);
+ constructor(flow, fn, description, opt_stackOptions, opt_isUserTask) {
+ super(flow, SKIP_LOG);
getUid(this);
/** @type {function(): (T|!ManagedPromise<T>)} */
@@ -2676,6 +2795,9 @@ class Task extends Deferred {
/** @type {TaskQueue} */
this.queue = null;
+ /** @private @const {boolean} */
+ this.userTask_ = !!opt_isUserTask;
+
/**
* Whether this task is considered block. A blocked task may be registered
* in a task queue, but will be dropped if it is still blocked when it
@@ -2889,7 +3011,7 @@ class TaskQueue extends events.EventEmitter {
}
// Now that all of the remaining tasks have been silently cancelled (e.g. no
- // exisitng callbacks on those tasks will fire), clear the silence bit on
+ // existing callbacks on those tasks will fire), clear the silence bit on
// the cancellation error. This ensures additional callbacks registered in
// the future will actually execute.
cancellation.silent_ = false;
@@ -2935,7 +3057,7 @@ class TaskQueue extends events.EventEmitter {
this.subQ_.once('end', () => { // On task completion.
this.subQ_ = null;
- this.pending_ && this.pending_.task.fulfill(result);
+ this.pending_ && this.pending_.task.resolve(result);
});
this.subQ_.once('error', e => { // On task failure.
@@ -3068,7 +3190,7 @@ class TaskQueue extends events.EventEmitter {
}
return task;
}
-};
+}
@@ -3214,7 +3336,7 @@ function consume(generatorFn, opt_self, ...var_args) {
function pump(fn, opt_arg) {
if (ret instanceof ManagedPromise && !isPending(ret)) {
- return; // Defererd was cancelled; silently abort.
+ return; // Deferred was cancelled; silently abort.
}
try {
@@ -3246,6 +3368,7 @@ module.exports = {
MultipleUnhandledRejectionError: MultipleUnhandledRejectionError,
Thenable: Thenable,
Promise: ManagedPromise,
+ Resolver: Resolver,
Scheduler: Scheduler,
all: all,
asap: asap,
@@ -3254,6 +3377,7 @@ module.exports = {
consume: consume,
controlFlow: controlFlow,
createFlow: createFlow,
+ createPromise: createPromise,
defer: defer,
delayed: delayed,
filter: filter,
@@ -3275,7 +3399,7 @@ module.exports = {
* The promise manager is currently enabled by default, but may be disabled
* by setting the environment variable `SELENIUM_PROMISE_MANAGER=0` or by
* setting this property to false. Setting this property will always take
- * precedence ove the use of the environment variable.
+ * precedence over the use of the environment variable.
*
* @return {boolean} Whether the promise manager is enabled.
* @see <https://github.com/SeleniumHQ/selenium/issues/2969>