设置为`run_at``document_start`的Chrome扩展程序运行得太快了?

Sha*_*dow 13 javascript google-chrome userscripts google-chrome-extension content-script

编辑:我的Chrome浏览器出现问题并与我的脚本产生冲突,无论问题来源是什么,都可以完全重新安装.如果我碰巧找出导致它的原因,我会把它包含在这里.

编辑2:只是为了让在2017年阅读此内容的人知道我没有忘记这一点,自从我之前的编辑以来我从未遇到过这个问题.

编辑3:这是2019年,到目前为止,我再也没遇到过这个问题.


我一直在学习如何创建一个简单的Chrome扩展程序,它是一个用户脚本端口.该脚本与Tampermonkey完美配合,设置run atdocument-start,所有需要从头开始捕获的必要事件都被捕获.

但是,当我在Chrome扩展程序中设置相同的设置时,我发现相同的运行设置比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"
}
Run Code Online (Sandbox Code Playgroud)

如果Chrome将采用该afterscriptexecute事件,所有这一切都可以避免,但在此之前,我仍然坚持这一load事件.我提前感谢你提供的任何帮助.


编辑:我已经尝试了回复中的建议:使用不同的run at点,使用DOMContentLoaded和追加document.documentElement.所有都不成功,因为:1和2使脚本错过早期事件,3返回与尝试追加时相同的TypeError document.head.

脚本必须插入/运行时document.readyState = loading,否则它将错过早期必要的事件,但不能太早到无法将孩子附加到其中documentElementhead

内部代码示例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);
}
Run Code Online (Sandbox Code Playgroud)

控制台将显示 TypeError: Cannot call method 'appendChild' of null

Bro*_*ams 21

Chrome扩展内容的脚本(从运行manifest.json是在运行)document_start,火之前document.readyState文件已经达到了interactive-这是你要开始与大多数网页元素搞乱最早的.

但是,<script>如果您愿意,可以立即注入大多数节点.只是不要document.headdocument.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);
Run Code Online (Sandbox Code Playgroud)

要么

var s = document.createElement ("script");
s.src = chrome.extension.getURL ("MyPwnCode.js");
s.async = false;
document.documentElement.appendChild (s);
Run Code Online (Sandbox Code Playgroud)

如果要添加或修改其他 DOM元素,请在运行的脚本中document_start等到DOMContentLoaded事件如下:

document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);

function fireContentLoadedEvent () {
    console.log ("DOMContentLoaded");
    // PUT YOUR CODE HERE.
    //document.body.textContent = "Changed this!";
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*lli 7

您的问题是,在使用时"run_at": "document_start",DOM中唯一允许存在的<html>元素是元素.如果你想避免相对于页面加载的错误,比如试图访问一些尚未创建的元素,你将不得不:

  • 让您的脚本运行"document_idle""document_end".虽然"document_end"仍然没有授予您页面的所有元素和资源都已完全加载(但DOM已经被解析),但该"document_idle"关键字将确保已经解析了DOM并且所有元素和资源都具有在脚本运行之前已正确加载.

  • 或者,您可以继续使用"document_start""DOMContentLoaded"侦听器中包装代码,这将使它在DOM完全加载和解析时运行,类似于"document_idle".这是一个例子:

    document.addEventListener("DOMContentLoaded", function() {
        // Run your code here...
    });
    
    Run Code Online (Sandbox Code Playgroud)

  • `document_idle`在**`document_end`之后发生** (3认同)
  • 你正在读它,但`window.onload`发生在`document_end`之后.`window.onload`表示[已加载所有资源](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers.onload),并且在DOM完成后`document_end`已经触发(这是更早的). (2认同)