39

executeAsyncScript 和 executeScript 有什么区别?如何使用诸如 window.onload 之类的事件?我尝试过这样的事情

((JavascriptExecutor) driver).executeAsyncScript("window.onload = function() {alert('Hello')}"); 

但是当然它没有用......所以如果有人知道它是如何工作的,请写一个例子

4

7 回答 7

30

(保持简单正确。)

execteScript和之间的相关区别executeAsyncScript是:

调用的函数executeAsyncScript将“完成回调”作为最后一个参数,必须调用它来表示脚本已完成执行。

这允许它与仅在使用回调时“完成”的代码一起使用 - 例如。setTimeout 或异步 XHR。如果在超时限制内未调用“完成回调”,则返回的承诺将被拒绝。

根据webdriver.WebDriver.executeAsyncScript文档:

与使用 #executeScript 执行同步 JavaScript 不同,使用 [#executeAsyncScript] 执行的脚本必须通过调用提供的回调显式地发出信号它们已完成。此回调将始终作为最后一个参数注入到执行的函数中。

也就是说,这两个函数都会阻塞 WebDriver 控制流,直到它们完成 - 要么在代码末尾运行,executeScript要么在调用“完成回调”时使用executeAsyncScript:名称中的“异步”表示使用的信号机制,并不意味着/暗示JavaScript 代码实际上是相对于 WebDriver 异步执行的。

于 2015-11-22T19:53:45.717 回答
26

我用executeScript. 提供的示例:

String cssSelector="...blablabla...";
JavascriptExecutor js = (JavascriptExecutor) driver;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("document.getElementById(\'"+cssSelector +"\').click();");
js.executeScript(stringBuilder.toString());

关于警报的详细信息,存在已知问题。你可以在这里获取详细信息

根据文档的区别是:

执行脚本

public java.lang.Object executeScript(java.lang.String script,
                             java.lang.Object... args)

从接口复制的描述:JavascriptExecutor 在当前选定的框架或窗口的上下文中执行 JavaScript。提供的脚本片段将作为匿名函数的主体执行。在脚本中,使用 document 来引用当前文档。请注意,一旦脚本完成执行,局部变量将不可用,但全局变量将保持不变。如果脚本有返回值(即如果脚本包含return语句),那么将采取以下步骤:

  • 对于 HTML 元素,此方法返回一个 WebElement
  • 对于小数,返回 Double
  • 对于非十进制数,返回 Long
  • 对于布尔值,返回一个布尔值
  • 对于所有其他情况,返回一个字符串。
  • 对于数组,返回一个 List,其中每个对象都遵循上述规则。我们支持嵌套列表。
  • 除非值为null或者没有返回值,其中返回null

参数必须是数字、布尔值、字符串、WebElement 或上述任意组合的列表。如果参数不符合这些条件,将引发异常。参数将通过“arguments”魔术变量提供给 JavaScript,就好像该函数是通过“Function.apply”调用的一样

指定者:接口 JavascriptExecutor 中的 executeScript 参数: script - 要执行的 JavaScript args - 脚本的参数。可能为空 返回:Boolean、Long、String、List 或 WebElement 之一。或为空。

执行异步脚本

public java.lang.Object executeAsyncScript(java.lang.String script,
                                  java.lang.Object... args)

从接口复制的描述:JavascriptExecutor 在当前选定的框架或窗口的上下文中执行一段异步的 JavaScript。与执行同步 JavaScript 不同,使用此方法执行的脚本必须通过调用提供的回调显式地表明它们已完成。此回调始终作为最后一个参数注入到执行的函数中。传递给回调函数的第一个参数将用作脚本的结果。该值的处理方式与同步情况相同。

示例 #1:在被测浏览器中执行休眠。

 long start = System.currentTimeMillis();
   ((JavascriptExecutor) driver).executeAsyncScript(
       "window.setTimeout(arguments[arguments.length - 1], 500);");
   System.out.println(
       "Elapsed time: " + (System.currentTimeMillis() - start));  

示例 #2:将测试与 AJAX 应用程序同步:

 WebElement composeButton = driver.findElement(By.id("compose-button"));
   composeButton.click();
   ((JavascriptExecutor) driver).executeAsyncScript(
       "var callback = arguments[arguments.length - 1];" +
       "mailClient.getComposeWindowWidget().onload(callback);");
   driver.switchTo().frame("composeWidget");
   driver.findElement(By.id("to")).sendKeys("bog@example.com");

示例 #3:注入 XMLHttpRequest 并等待结果:

 Object response = ((JavascriptExecutor) driver).executeAsyncScript(
       "var callback = arguments[arguments.length - 1];" +
       "var xhr = new XMLHttpRequest();" +
       "xhr.open('GET', '/resource/data.json', true);" +
       "xhr.onreadystatechange = function() {" +
       "  if (xhr.readyState == 4) {" +
       "    callback(xhr.responseText);" +
       "  }" +
       "}" +
       "xhr.send();");
   JSONObject json = new JSONObject((String) response);
   assertEquals("cheese", json.getString("food"));

脚本参数必须是数字、布尔值、字符串、WebElement 或上述任意组合的列表。如果参数不符合这些条件,将引发异常。这些参数将通过“arguments”变量提供给 JavaScript。

指定者:接口 JavascriptExecutor 中的 executeAsyncScript 参数: script - 要执行的 JavaScript。args - 脚本的参数。可能是空的。返回: Boolean、Long、String、List、WebElement 或 null 之一。

详细文档在这里

于 2012-11-19T12:34:01.093 回答
9

它们之间的主要区别在于,使用 async 执行的脚本必须通过调用提供的回调显式地表示它们已完成。此回调始终作为最后一个参数注入到执行的函数中。

于 2014-05-30T07:57:08.520 回答
3
((JavascriptExecutor) driver).executeScript("alert('Hello');"); 

将显示警报:

((JavascriptExecutor) 驱动程序).executeAsyncScript() 用于当 JS 需要时间来执行例如 Web 服务调用时。

window.onload确保页面完全加载时执行 JS。

于 2012-11-19T14:55:39.563 回答
2

我花了很多时间来理解这个功能,最后我得到了它。以下代码将有很大帮助:

/**
 * executeAsyncScript document mentioned callback is a browser intrinsic function for returning deferred value (e.g 123 in example) from
 * js environment to Java environment
 * 
 */
@Test
public void testAsyncScript() {
    webDriver.manage().timeouts().setScriptTimeout(1, TimeUnit.SECONDS);
    Integer a = 23;
    TestUtil.elapse("first", () -> {
        Object value = getJsExecutor().executeAsyncScript("window.setTimeout(arguments[arguments.length - 1](123), 500);", a);
        // following code should be executed after 500ms timeout
        System.out.println("a is " + a); // a has nothing to do with the documented "callback"
        assertEquals(123, value);
    });

}
于 2017-03-13T14:04:33.837 回答
0

您可以执行以下操作:

JavascriptExecutor js=(JavascriptExecutor)driver;
String javascript="window.location='https://google.com';window.onload=alert('hello'); var callback=arguments[arguments.length-1]; callback();";
        js.executeAsyncScript(javascript);
    

正如其他人所说,executeAsyncScript() 使用称为回调的信号机制来向主函数/代码发出信号,表明 executeAsyncScript 中的 javascript 已完成。回调被称为参数[arguments.length-1]。

于 2021-12-29T14:51:52.283 回答
0

这个简单的 Async 脚本监听 DOM 上点击的元素并通过回调解析executeAsyncScript

  var clicked_element = await driver.executeAsyncScript('var callback=arguments[arguments.length - 1]; window.document.addEventListener("click", function(e){ var element = event.srcElement ||event.target; callback(element); });'); 
于 2020-07-01T15:40:28.113 回答