[英]Chrome extension set to `run_at` `document_start` is running too fast?
EDIT: Something was wrong with my Chrome browser and creating a conflict with my script, a full reinstall eliminated whatever the problem source was. 编辑:我的Chrome浏览器出现问题并与我的脚本产生冲突,无论问题来源是什么,都可以完全重新安装。 If I happen to find out what was causing it I will include it in here.
如果我碰巧找出导致它的原因,我会把它包含在这里。
EDIT2: Just to let anyone reading this in 2017 know that I haven't forgotten this and I have never had this problem since my previous edit. 编辑2:只是为了让在2017年阅读此内容的人知道我没有忘记这一点,自从我之前的编辑以来我从未遇到过这个问题。
EDIT3: It is 2019 and so far I've never had this problem again. 编辑3:这是2019年,到目前为止,我再也没遇到过这个问题。
I have been learning how to create a simple Chrome extension which is a userscript port. 我一直在学习如何创建一个简单的Chrome扩展程序,这是一个用户脚本端口。 The script works perfectly with Tampermonkey with the setting
run at
to document-start
, all the necessary events that need to be caught from the beginning are all captured. 该脚本与Tampermonkey完美配合,设置
run at
到document-start
,所有需要document-start
捕获的必要事件都被捕获。
However, when I set the same settings in the Chrome extension I discovered that the same running setting is faster than Tampermonkey's which causes the first function to fail: ( Uncaught TypeError: Cannot call method 'appendChild' of null.
) since it tries to append a script element to the head
section, which doesn't exist until 0.010s later. 但是,当我在Chrome扩展程序中设置相同的设置时,我发现相同的运行设置比Tampermonkey更快,导致第一个函数失败:(
Uncaught TypeError: Cannot call method 'appendChild' of null.
)因为它试图追加head
部分的脚本元素,直到0.010s后才存在。
My dirty solution so far has been to make use of a setInterval
function with the timer set to 10 to check if document.head
exists and then proceed with the code if the condition is true. 到目前为止,我的脏解决方案是使用
setInterval
函数,将计时器设置为10来检查document.head
存在,然后在条件为真时继续执行代码。
Is there any way that I can make this work correctly without having to resort to setInterval
or maybe replicate Tampermonkey's grant none
option which appears to run the userscript on the webpage context? 有没有什么方法可以让我正确地工作,而不必诉诸于
setInterval
或者可能复制Tampermonkey的grant none
选项,它似乎在网页上下文中运行用户脚本?
The following is my manifest.json file: 以下是我的manifest.json文件:
{
"manifest_version": 2,
"content_scripts": [ {
"js": [ "simpleuserscript.user.js" ],
"matches": [ "https://www.google.com/*"],
"run_at": "document_start"
} ],
"converted_from_user_script": true,
"description": "Chrome extension",
"name": "Testing",
"version": "1"
}
All of this could be avoided if Chrome would adopt the afterscriptexecute
event, but until that happens I am stuck with the load
event. 如果Chrome会采用
afterscriptexecute
事件,所有这一切都可以避免,但在此之前我会遇到load
事件。 I thank in advance any help provided. 我提前感谢你提供的任何帮助。
EDIT: I have already tried the suggestions in the replies: using a different run at
point, using DOMContentLoaded
and append to document.documentElement
. 编辑:我已经尝试了回复中的建议:使用不同的
run at
点,使用DOMContentLoaded
加到document.documentElement
。 All were unsuccessful because: 1 and 2 makes the script miss early events, and 3 returns the same TypeError as when trying to append to document.head
. 所有都不成功,因为:1和2使脚本错过早期事件,3返回与尝试追加到
document.head
时相同的TypeError。
The script has to be inserted/running when document.readyState = loading
or else it will miss early necessary events, but not so early to the point of being unable to append childs to either documentElement
or head
当
document.readyState = loading
时,必须插入/运行该脚本,否则它将错过早期必要事件,但不能太早到无法将子项附加到documentElement
或head
An example of the code inside simpleuserscript.user.js
: simpleuserscript.user.js
中的代码simpleuserscript.user.js
:
var script = document.createElement("script");
script.textContent = "console.log('success')";
if(document.head) {
document.head.appendChild(script);
} else if(document.documentElement) {
document.documentElement.appendChild(script);
}
Console will show TypeError: Cannot call method 'appendChild' of null
控制台将显示
TypeError: Cannot call method 'appendChild' of null
Chrome extension Content scripts (run from a manifest.json
) that are run at document_start
, do fire before document.readyState
Doc has reached interactive
-- which is the earliest you want to start messing with most page elements. Chrome扩展内容的脚本 (从运行
manifest.json
是在运行) document_start
, 做火之前document.readyState
文件已经达到interactive
-这是你要开始与大多数网页元素搞乱最早的。
However, you can inject most <script>
nodes right away if you wish. 但是,如果您愿意,可以立即注入大多数
<script>
节点。 Just not to document.head
or document.body
because they don't exist yet. 只是不要
document.head
或document.body
因为它们还不存在。
Append to documentElement
instead. 追加到
documentElement
。 For example: 例如:
var s = document.createElement ("script");
s.src = "http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js";
s.async = false;
document.documentElement.appendChild (s);
Or 要么
var s = document.createElement ("script");
s.src = chrome.extension.getURL ("MyPwnCode.js");
s.async = false;
document.documentElement.appendChild (s);
If you are adding or modifying other DOM elements, in a script running at document_start
, wait until the DOMContentLoaded
event like so: 如果要添加或修改其他 DOM元素,请在运行
document_start
的脚本中等待DOMContentLoaded
事件,如下所示:
document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
function fireContentLoadedEvent () {
console.log ("DOMContentLoaded");
// PUT YOUR CODE HERE.
//document.body.textContent = "Changed this!";
}
Your problem is that, when using "run_at": "document_start"
, the only element that is granted to exist in the DOM is the <html>
element. 您的问题是,当使用
"run_at": "document_start"
,DOM中唯一被授予的元素是<html>
元素。 If you want to avoid errors relative to page load, like trying to access some element that hasn't been created yet, you'll have to either: 如果你想避免相对于页面加载的错误,比如试图访问一些尚未创建的元素,你将不得不:
Make your script run at "document_idle"
or "document_end"
. 使您的脚本在
"document_idle"
或"document_end"
。 Although "document_end"
still doesn't grant you that all the elements and resources of the page have been fully loaded (but the DOM has already been parsed), the "document_idle"
keyword will give you the certainty that the DOM has been parsed and all the elements and resources have been loaded properly before your script runs. 虽然
"document_end"
仍然没有授予您页面的所有元素和资源都已完全加载(但DOM已经被解析),但"document_idle"
关键字将确保DOM已被解析并且在脚本运行之前已正确加载所有元素和资源。
Or, instead, you can continue using "document_start"
wrapping your code inside a "DOMContentLoaded"
listener, which will make it run when the DOM has completely finished loading and parsing, similarly to "document_idle"
. 或者,您可以继续使用
"document_start"
将代码包装在"DOMContentLoaded"
侦听器中,这将使DOM在完全加载和解析时运行,类似于"document_idle"
。 Here's an example: 这是一个例子:
document.addEventListener("DOMContentLoaded", function() { // Run your code here... });
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.