Chrome 扩展设置为 `run_at` `document_start` 是 运行 太快了吗?
Chrome extension set to `run_at` `document_start` is running too fast?
编辑:我的 Chrome 浏览器出了点问题,并与我的脚本发生冲突,完全重新安装消除了问题的来源。如果我碰巧找出是什么原因造成的,我会把它包括在这里。
EDIT2:只是为了让 2017 年阅读这篇文章的人知道我没有忘记这一点,而且自从我上次编辑以来我从未遇到过这个问题。
EDIT3:现在是 2019 年,到目前为止我再也没有遇到过这个问题。
我一直在学习如何创建一个简单的 Chrome 扩展,它是一个用户脚本端口。该脚本与 Tampermonkey 完美配合,设置 run at
到 document-start
,所有需要从头开始捕获的必要事件都被捕获。
然而,当我在 Chrome 扩展中设置相同的设置时,我发现相同的 运行ning 设置比 Tampermonkey 的设置更快,这导致第一个功能失败:(Uncaught TypeError: Cannot call method 'appendChild' of null.
) 因为它试图将脚本元素附加到 head
部分,该部分直到 0.010 秒后才存在。
到目前为止,我的肮脏解决方案是使用 setInterval
函数并将计时器设置为 10 来检查 document.head
是否存在,然后在条件为真时继续执行代码。
有什么方法可以使它正常工作而不必求助于 setInterval
或者复制 Tampermonkey 的 grant none
选项,该选项出现在 运行 网页上下文的用户脚本中?
以下是我的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"
}
如果 Chrome 采用 afterscriptexecute
事件,所有这一切都可以避免,但在那之前我一直坚持 load
事件。我提前感谢提供的任何帮助。
编辑:我已经尝试过回复中的建议:使用不同的 run at
点,使用 DOMContentLoaded
并附加到 document.documentElement
。全部都不成功,因为:1 和 2 使脚本错过了早期事件,以及 3 returns 与尝试附加到 document.head
.
时相同的 TypeError
当 document.readyState = loading
时脚本必须是 inserted/running 否则它会错过早期的必要事件,但不会太早到无法将子项附加到 documentElement
的地步或 head
里面的代码示例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);
}
控制台将显示 TypeError: Cannot call method 'appendChild' of null
您的问题是,当使用 "run_at": "document_start"
时,唯一允许存在于 DOM 中的元素是 <html>
元素。如果你想避免与页面加载有关的错误,比如试图访问一些尚未创建的元素,你必须:
在 "document_idle"
或 "document_end"
处制作脚本 运行。虽然 "document_end"
仍然不授予您页面的所有元素和资源已完全加载(但 DOM 已经被解析),但 "document_idle"
关键字会给您确定 DOM 已被解析并且所有元素和资源都已在您的脚本 运行s.
之前正确加载
或者,您可以继续使用 "document_start"
将您的代码包装在 "DOMContentLoaded"
侦听器中,当 DOM已经完全完成加载和解析,类似于"document_idle"
。这是一个例子:
document.addEventListener("DOMContentLoaded", function() {
// Run your code here...
});
Chrome 扩展 内容脚本 (来自 manifest.json
的 运行)运行 在 document_start
, do 在 document.readyState
Doc 达到 interactive
之前触发 - 这是您想要开始弄乱大多数页面元素的最早时间。
但是,您可以根据需要立即注入大多数 <script>
节点。只是不要 document.head
或 document.body
因为它们还不存在。
改为附加到 documentElement
。例如:
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);
或
var s = document.createElement ("script");
s.src = chrome.extension.getURL ("MyPwnCode.js");
s.async = false;
document.documentElement.appendChild (s);
如果您要添加或修改 other DOM 元素,请在脚本 运行ning at document_start
中,等待 DOMContentLoaded
像这样的事件:
document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
function fireContentLoadedEvent () {
console.log ("DOMContentLoaded");
// PUT YOUR CODE HERE.
//document.body.textContent = "Changed this!";
}
编辑:我的 Chrome 浏览器出了点问题,并与我的脚本发生冲突,完全重新安装消除了问题的来源。如果我碰巧找出是什么原因造成的,我会把它包括在这里。
EDIT2:只是为了让 2017 年阅读这篇文章的人知道我没有忘记这一点,而且自从我上次编辑以来我从未遇到过这个问题。
EDIT3:现在是 2019 年,到目前为止我再也没有遇到过这个问题。
我一直在学习如何创建一个简单的 Chrome 扩展,它是一个用户脚本端口。该脚本与 Tampermonkey 完美配合,设置 run at
到 document-start
,所有需要从头开始捕获的必要事件都被捕获。
然而,当我在 Chrome 扩展中设置相同的设置时,我发现相同的 运行ning 设置比 Tampermonkey 的设置更快,这导致第一个功能失败:(Uncaught TypeError: Cannot call method 'appendChild' of null.
) 因为它试图将脚本元素附加到 head
部分,该部分直到 0.010 秒后才存在。
到目前为止,我的肮脏解决方案是使用 setInterval
函数并将计时器设置为 10 来检查 document.head
是否存在,然后在条件为真时继续执行代码。
有什么方法可以使它正常工作而不必求助于 setInterval
或者复制 Tampermonkey 的 grant none
选项,该选项出现在 运行 网页上下文的用户脚本中?
以下是我的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"
}
如果 Chrome 采用 afterscriptexecute
事件,所有这一切都可以避免,但在那之前我一直坚持 load
事件。我提前感谢提供的任何帮助。
编辑:我已经尝试过回复中的建议:使用不同的 run at
点,使用 DOMContentLoaded
并附加到 document.documentElement
。全部都不成功,因为:1 和 2 使脚本错过了早期事件,以及 3 returns 与尝试附加到 document.head
.
当 document.readyState = loading
时脚本必须是 inserted/running 否则它会错过早期的必要事件,但不会太早到无法将子项附加到 documentElement
的地步或 head
里面的代码示例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);
}
控制台将显示 TypeError: Cannot call method 'appendChild' of null
您的问题是,当使用 "run_at": "document_start"
时,唯一允许存在于 DOM 中的元素是 <html>
元素。如果你想避免与页面加载有关的错误,比如试图访问一些尚未创建的元素,你必须:
在
"document_idle"
或"document_end"
处制作脚本 运行。虽然"document_end"
仍然不授予您页面的所有元素和资源已完全加载(但 DOM 已经被解析),但"document_idle"
关键字会给您确定 DOM 已被解析并且所有元素和资源都已在您的脚本 运行s. 之前正确加载
或者,您可以继续使用
"document_start"
将您的代码包装在"DOMContentLoaded"
侦听器中,当 DOM已经完全完成加载和解析,类似于"document_idle"
。这是一个例子:document.addEventListener("DOMContentLoaded", function() { // Run your code here... });
Chrome 扩展 内容脚本 (来自 manifest.json
的 运行)运行 在 document_start
, do 在 document.readyState
Doc 达到 interactive
之前触发 - 这是您想要开始弄乱大多数页面元素的最早时间。
但是,您可以根据需要立即注入大多数 <script>
节点。只是不要 document.head
或 document.body
因为它们还不存在。
改为附加到 documentElement
。例如:
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);
或
var s = document.createElement ("script");
s.src = chrome.extension.getURL ("MyPwnCode.js");
s.async = false;
document.documentElement.appendChild (s);
如果您要添加或修改 other DOM 元素,请在脚本 运行ning at document_start
中,等待 DOMContentLoaded
像这样的事件:
document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
function fireContentLoadedEvent () {
console.log ("DOMContentLoaded");
// PUT YOUR CODE HERE.
//document.body.textContent = "Changed this!";
}