admin管理员组文章数量:1201805
I am having some problem with the order of javascript execution when I use the content script to inject some javascript into the HTML page:
This is my HTML page I use to test, test.html:
<html><head>
<title>Test Page</title></head>
<body>
<script>
console.log("In page");
</script>
</body>
</html>
This is the javascript I use to inject additional code into HTML page, injector.js:
var s = document.createElement("script");
s.src = chrome.extension.getURL("inject.js");
document.documentElement.appendChild(s);
console.log("Inject finished");
And this is the content of injected script, inject.js:
console.log("Inside inject.js");
And finally, this is my manifest.json:
"web_accessible_resources": [
"inject.js"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["/injector.js"],
"run_at": "document_start"
}
]
Now, when I open up the test.html, this is what I got in my console:
Inject finished
In page
Inside inject.js
My question is, why is In page
printed out before Inside inject.js
? Isn't inject.js
supposed to be run first since I set the run_at
to document_start
?
If this is by design, is there any way I can make sure that the content inside inject.js is executed before the script inside the HTML page while not changing anything inside the HTML page?
Setting the async
attribute to false
before appendChild
doesn't seem to work since it is used for the ordering between the external scripts, not between external scripts and in-page script.
BTW, I am testing this on Chrome 27.0.1453.9
I am having some problem with the order of javascript execution when I use the content script to inject some javascript into the HTML page:
This is my HTML page I use to test, test.html:
<html><head>
<title>Test Page</title></head>
<body>
<script>
console.log("In page");
</script>
</body>
</html>
This is the javascript I use to inject additional code into HTML page, injector.js:
var s = document.createElement("script");
s.src = chrome.extension.getURL("inject.js");
document.documentElement.appendChild(s);
console.log("Inject finished");
And this is the content of injected script, inject.js:
console.log("Inside inject.js");
And finally, this is my manifest.json:
"web_accessible_resources": [
"inject.js"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["/injector.js"],
"run_at": "document_start"
}
]
Now, when I open up the test.html, this is what I got in my console:
Inject finished
In page
Inside inject.js
My question is, why is In page
printed out before Inside inject.js
? Isn't inject.js
supposed to be run first since I set the run_at
to document_start
?
If this is by design, is there any way I can make sure that the content inside inject.js is executed before the script inside the HTML page while not changing anything inside the HTML page?
Setting the async
attribute to false
before appendChild
doesn't seem to work since it is used for the ordering between the external scripts, not between external scripts and in-page script.
BTW, I am testing this on Chrome 27.0.1453.9
Share Improve this question edited Mar 31, 2013 at 22:36 Brock Adams 93.4k23 gold badges240 silver badges304 bronze badges asked Mar 31, 2013 at 15:13 HeryHery 7,6199 gold badges38 silver badges41 bronze badges4 Answers
Reset to default 16Injected scripts, with src
attributes are executed asynchronously in Chrome.
Consider this HTML file:
<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>
where localInject1.js is just:
console.log("In page's script 1: ", new Date().getTime());
and localInject2.js is:
console.log("In page's script 2: ", new Date().getTime());
Nominally, the console should show:
In page's script 1: ...
In page's script 2: ...
In page: ...
But frequently, and especially on cache-less reloads, you'll see:
In page's script 2: ...
In page: ...
In page's script 1: ...
Setting s.async = false;
makes no difference.
I'm not sure if this is a bug or not. Firefox also gets the scripts out of order, but seems more consistent about it. There don't seem to be any relevant Chrome bugs, and the specs are unclear to me.
Work around:
Scripts with code set by textContent
, rather than a file linked by src
, execute immediately as you would expect.
For example, if you changed injector.js to:
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() );
you would see:
Text runs correctly! ...
Inject finished ...
In page
Inside inject.js
Admittedly this can be a pain in a content script, but it may be all you can do (in Chrome) until this issue is resolved by the W3C and browser vendors.
JavaScript script
tags are not blocking the execution (thankfully!). If you'd like to get the kind of functionality you want (lazy-loading), you'll need to do something like the following:
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();
}
};
}
This will fire a callback function when the script tag is loaded. From there, load everything and make sure that every callback is processed, then fire your page-load events in the sanity of mind that you have every library you need.
When you inject javascript onto the page like that, it comes in asynchronously. When you actually have the <script>
tag in there from the beginning, it will be synchronous and run in the correct order.
Kind of a hassle, but since it's asynchronous, your code will continue to execute while the other script file is being loaded.
In order to know when the script is complete, you have to handle the event for the script - easiest way is using jQuery's getScript
function, which provides you a callback argument.
There are entire libraries dedicated to achieving what you are trying to do, as each browser seems to add its own share of bugs. Have a look at something like HeadJS, or if already using jQuery what joe said.
本文标签:
版权声明:本文标题:google chrome extension - My injected <script> runs after the target-page's javascript, despite using run_ 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738564015a2099789.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论