繁体   English   中英

我注入的<script>在目标页面的javascript之后运行,尽管使用了run_at:document_start?

[英]My injected <script> runs after the target-page's javascript, despite using run_at: document_start?

当我使用内容脚本将一些javascript注入HTML页面时,我遇到了javascript执行顺序的一些问题:

这是我用来测试的HTML页面, test.html

<html><head>    
<title>Test Page</title></head>
  <body>
    <script>
      console.log("In page");
    </script>
  </body>
</html>


这是我用来向HTML页面注入额外代码的javascript: injector.js

var s = document.createElement("script");
s.src = chrome.extension.getURL("inject.js");
document.documentElement.appendChild(s);
console.log("Inject finished");


这是注入脚本的内容, inject.js

console.log("Inside inject.js");


最后,这是我的manifest.json

  "web_accessible_resources": [
    "inject.js"
  ],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["/injector.js"],
      "run_at": "document_start"
    }
  ]


现在,当我打开test.html时 ,这就是我在控制台中得到的:

Inject finished
In page
Inside inject.js


我的问题是,为什么在Inside inject.js之前打印出In page 是不是inject.js应该因为我设置应首先运行run_atdocument_start

如果这是设计的,有什么方法可以确保inject.js中的内容在HTML页面内的脚本之前执行而不改变HTML页面内的任何内容

appendChild之前将async属性设置为false似乎不起作用,因为它用于外部脚本之间的排序,而不是外部脚本和页内脚本之间的排序。

顺便说一句,我在Chrome 27.0.1453.9上测试了这个

具有src属性的注入脚本在Chrome中异步执行。
考虑这个HTML文件:

<html><head>
    <title>Chrome early script inject, Test Page</title>
    <script>
        var s = document.createElement ("script");
        s.src = "localInject1.js";
        document.documentElement.appendChild (s);
    </script>
</head>
<body>
<p>See the console.</p>
<script src="localInject2.js"></script>
<script> console.log("In page: ", new Date().getTime()); </script>
</body>
</html>

localInject1.js只是:

console.log("In page's script 1: ", new Date().getTime());

localInject2.js是:

console.log("In page's script 2: ", new Date().getTime());


名义上,控制台应显示:

In page's script 1:   ...
In page's script 2:   ...
In page:   ...


但经常,特别是在无缓存重新加载时,您会看到:

In page's script 2:   ...
In page:   ...
In page's script 1:   ...


设置s.async = false; 没有区别。


我不确定这是不是一个bug。 Firefox也不按顺序获取脚本,但似乎更加一致。 似乎没有任何相关的Chrome错误 ,我不清楚这些规格。


解决方法:

使用textContent设置的代码的脚本,而不是由src链接的文件,可以像您期望的那样立即执行。
例如,如果您将injector.js更改为:

var s = document.createElement ("script");
s.src = chrome.extension.getURL ("inject.js");
document.documentElement.appendChild (s);

var s = document.createElement ('script');
s.textContent = 'console.log ("Text runs correctly!", new Date().getTime() );';
document.documentElement.appendChild (s);

console.log("Inject finished", new Date().getTime() );

你会看到:

Text runs correctly! ...
Inject finished ...
In page
Inside inject.js


不可否认,这可能是内容脚本的一个难点,但在W3C和浏览器供应商解决此问题之前,您可以做任何事情(在Chrome中)。

JavaScript script标记不会阻止执行(谢天谢地!)。 如果您想获得所需的功能(延迟加载),您需要执行以下操作:

function loadScript(scriptName, callback) {
   var sTag = document.createElement("script");
   sTag.src = scriptName;
   sTag.onreadystatechange = sTag.onload = function() {
    var state = s.readyState;

    if (!state || /loaded|complete/.test(state)) {
        callback();
    }
  };
 }

这将在加载脚本标记时触发回调函数。 从那里,加载所有内容并确保每个回调都得到处理,然后以您需要的每个库的精神状态启动页面加载事件。

当您将javascript注入页面时,它会以异步方式进入。 当你从头开始实际拥有<script>标签时,它将是同步的并以正确的顺序运行。

有点麻烦,但由于它是异步的,你的代码将在加载另一个脚本文件时继续执行。

为了知道脚本何时完成,您必须处理脚本的事件 - 最简单的方法是使用jQuery的getScript函数,它为您提供回调参数。

有完整的库专门用于实现您要做的事情,因为每个浏览器似乎都添加了自己的bug。 看看像HeadJS这样的东西,或者如果已经使用jQuery,乔说了什么。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM