当我使用内容脚本将一些 javascript 注入(inject) HTML 页面时,javascript 的执行顺序有问题:
这是我用来测试的 HTML 页面,test.html:
<html><head>
<title>Test Page</title></head>
<body>
<script>
console.log("In page");
</script>
</body>
</html>
这是我用来将额外代码注入(inject) 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)脚本 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
?自从我将 run_at
设置为 document_start
后,难道 inject.js
应该首先运行吗?
如果这是设计使然,有什么方法可以确保 inject.js 中的内容在 HTML 页面中的脚本之前执行,同时不更改 HTML 页面中的任何内容?
在 appendChild
之前将 async
属性设置为 false
似乎不起作用,因为它用于外部脚本之间的排序,不在外部脚本和页内脚本之间。
顺便说一句,我正在 Chrome 27.0.1453.9 上测试这个
最佳答案
带有 src
属性的注入(inject)脚本在 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;
没有任何区别。
我不确定这是不是一个错误。 Firefox 也会让脚本乱序,但似乎更一致。好像没有any relevant Chrome bugs ,我不清楚规范。
解决方法:
代码由 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 和浏览器 vendor 解决此问题之前,您可能(在 Chrome 中)只能这样做。
关于javascript - 尽管使用 run_at : document_start?,但我注入(inject)的 <script> 在目标页面的 javascript 之后运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15730869/