From 8202fd0d3ad5c488009e9b828001e52461147548 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Fri, 26 Oct 2018 22:25:53 -0400 Subject: [PATCH] Correct specification of parallel operations Prior to this patch, parallelism in the Execute Script and Execute Async Script commands was expressed in terms of ECMAScript promises. This was ambiguous because in HTML, Promises rely on an environment settings object [1], and such an object is not generally available in the WebDriver execution context. Refactor the command algorithms to instead manage parallel execution using the generic "queue" primitive from the Infra specification. Refactor the "execute a function body" algorithm to use Promises, where following the invocation of "prepare to run a script," an environment settings object is available. [1] https://html.spec.whatwg.org/#integration-with-the-javascript-job-queue --- index.html | 182 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 103 insertions(+), 79 deletions(-) diff --git a/index.html b/index.html index f04ea5dfc..b1037a5f4 100644 --- a/index.html +++ b/index.html @@ -6066,12 +6066,13 @@

Executing Script

and arguments. -

The rules to execute a function body are as follows. - The algorithm returns an ECMASCript completion record. +

When required to execute a function body with arguments + body, arguments, and async, the + implementation must:

If at any point during the algorithm a user prompt appears, abort all subsequent substeps of this algorithm, and return - Completion { [[\Type]]: normal, [[\Value]]: null, [[\Target]]: empty }. + success with data null.

  1. Let window be the associated window @@ -6086,8 +6087,7 @@

    Executing Script

  2. If body is not parsable as a FunctionBody or if parsing detects an early error, - return - Completion { [[\Type]]: normal, [[\Value]]: null, [[\Target]]: empty }. + return error with error code javascript error.

  3. If body begins with a directive prologue that contains a use strict directive @@ -6098,6 +6098,17 @@

    Executing Script

  4. Prepare to run a callback with environment settings. +

  5. Let promise be a new Promise. + +

  6. If async is true: + +

      +
    1. Let resolvingFunctions be CreateResolvingFunctions(promise). + +

    2. Append resolvingFunctions.[[\Resolve]] + to arguments. +

    +
  7. Let function be the result of calling FunctionCreate, with arguments: @@ -6121,7 +6132,37 @@

    Executing Script

  8. Let completion be Call(function, window, - parameters). + arguments). + +

  9. If completion.[[\Type]] is throw, + reject promise with completion.[[\Value]]. + +

  10. Otherwise, if async is false, + resolve promise with completion.[[\Value]]. + +

  11. Otherwise, + +

      +

      Prior revisions of this specification did not recognize the + return value of the provided script. In order to preserve legacy behavior, + the return value only influences this algorithm if it is a "thenable" object or + if determining this produces an exception. + +

    1. If Type(completion.[[\Value]]) + is Object: + +

        +
      1. Let then be Get(completion.[[\Value]], "then"). + +

      2. If then.[[\Type]] is not normal, then reject + promise with value then.[[\Value]]. + +

      3. Otherwise, if IsCallable(then.[[\Value]]) is + true, then resolve promise with completion.[[\Value]]. +

      +
    + +
  12. Wait for promise to settle.

  13. Clean up after running a callback with environment settings. @@ -6129,7 +6170,20 @@

    Executing Script

  14. Clean up after running a script with environment settings. -

  15. Return completion. +

  16. If promise rejected: + +

      +
    1. Let result be the result of trying to + JSON clone the rejection value of promise. + +

    2. Return error with error code javascript error + and data result. +

    + +
  17. Let result be the result of trying to + JSON clone the fulfillment value of promise. + +

  18. Return success with data result.

The above algorithm is not associated @@ -6162,33 +6216,32 @@

Execute Script

  • Handle any user prompts, and return its value if it is an error. -

  • Let promise be a new Promise. +

  • Let results be a new queue.

  • Run the following substeps in parallel: -

      -
    1. Let scriptPromise be the result of promise-calling - execute a function body, with arguments - body and arguments. -

    2. Upon fulfillment of scriptPromise with value v, - resolve promise with value v. +

        +
      1. Let script result be the result of calling + execute a function body, with arguments + body, arguments, and false. -

      2. Upon rejection of scriptPromise with value r, - reject promise with value r. -

      +
    3. Enqueue script result in results. +

    + +
  • Run the following substeps in parallel: + +

      +
    1. Wait session script timeout milliseconds. + +

    2. Enqueue error with error code + script timeout in results. +

    -
  • If promise is still pending and - the session script timeout is reached, - return error with error code script timeout. +

  • Wait for the size of results to be greater than 0. -

  • Upon fulfillment of promise with value v, - let result be a JSON clone of v, and - return success with data result. +

  • Dequeue result from results. -

  • Upon rejection of promise with reason r, - let result be a JSON clone of r, and - return error with error code javascript error - and data result. +

  • Return result. @@ -6216,69 +6269,41 @@

    Execute Async Script

    The remote end steps are:

      -
    1. Let body and arguments by the result of trying to - extract the script arguments from a request with - argument parameters. - -

    2. If the current browsing context is no longer open, - return error with error code no such window. - -

    3. Handle any user prompts, and return its value if it is an error. - -

    4. Let promise be a new Promise. - -

    5. Run the following substeps in parallel: -

        -
      1. Let resolvingFunctions be CreateResolvingFunctions(promise). - -

      2. Append resolvingFunctions.[[\Resolve]] to - arguments. - -

      3. Let result be the result of calling - execute a function body, with arguments - body and arguments. +

      4. Let body and arguments be the result of + trying to extract the script arguments from a request + with argument parameters. -

      5. If scriptResult.[[\Type]] is not normal, then reject - promise with value scriptResult.[[\Value]], and abort these steps. +

      6. If the current browsing context is no longer open, + return error with error code no such window. -

        Prior revisions of this specification did not recognize the - return value of the provided script. In order to preserve legacy behavior, - the return value only influences the command if it is a "thenable" object or - if determining this produces an exception. +

      7. Handle any user prompts, and return its value if it is an error. -

      8. If Type(scriptResult.[[\Value]]) - is not Object, then abort these steps. +

      9. Let results be a new queue. -

      10. Let then be Get(scriptResult.[[\Value]], "then"). +

      11. Run the following substeps in parallel: -

      12. If then.[[\Type]] is not normal, then reject - promise with value then.[[\Value]], and abort these steps. +

          +
        1. Let script result be the result of calling + execute a function body, with arguments + body, arguments, and true. -

        2. If IsCallable(then.[[\Type]]) is false, - then abort these steps. +

        3. Enqueue script result in results. +

        -
      13. Let scriptPromise be PromiseResolve(Promise, - scriptResult.[[\Value]]). +

      14. Run the following substeps in parallel: -

      15. Upon fulfillment of scriptPromise with value v, - resolve promise with value v. +

          +
        1. Wait session script timeout milliseconds. -

        2. Upon rejection of scriptPromise with value r, - reject promise with value r. -

        +
      16. Enqueue error with error code + script timeout in results. +

      -
    6. If promise is still pending and - session script timeout milliseconds is reached, - return error with error code script timeout. +

    7. Wait for the size of results to be greater than 0. -

    8. Upon fulfillment of promise with value v, - let result be a JSON clone of v, and - return success with data result. +

    9. Dequeue result from results. -

    10. Upon rejection of promise with reason r, - let result be a JSON clone of r, and - return error with error code javascript error - and data result. +

    11. Return result.

    @@ -9299,7 +9324,6 @@

    Index

    The following terms are defined in the ECMAScript Language Specification: [[ECMA-262]]