如何让内容脚本在页面Javascript执行后加载?

48

我的扩展应该在被注入的页面完全加载后才加载一个名为searchTopic.js的内容脚本(是的,我已经在扩展清单中将"run_at"设置为"document_end"),但实际上它在DOM对象全部创建之前就已经加载了(其中关键对象是通过页面中的一些Javascript创建的)。所以问题是,我如何等待页面的Javascript执行完毕?这是我的清单:

"content_scripts": [
  {
  "run_at": "document_end",
  "matches": ["https://groups.google.com/forum/*"],
  "js": ["searchTopic.js"]
  }
],

2
你无法预测未来。你找到的任何解决方案都是针对你编写脚本的特定情况而言的。尝试使用 window.onload 事件进行操作,或者通过一种轮询方式使用计时器来检测页面是否处于所需状态。 - Rob W
你无法知道何时所有的JavaScript代码都已执行完毕。它在解析时只运行一次,但其操作(DOM操作、进一步的脚本加载)可能会在稍后发生,由任何事件触发 - 我担心这些对你很有趣。 - Bergi
3个回答

77

"run_at": "document_end" 相当于 DOMContentLoaded。也就是说,它会在静态 HTML 加载完毕后触发,但在缓慢加载的图像和 JavaScript 完成之前。

因此,你不能仅通过设置清单来设置内容脚本在页面 JS 之后运行。你必须在内容脚本中编写代码。

对于内容脚本,"run_at": "document_end" 会在 onload 事件之前触发(与默认值 document_idle 不同,后者可能在不可预测的时间触发)。

因此,第一步是使用类似以下代码等待 load 事件,在你的内容脚本 (searchTopic.js) 中:

window.addEventListener ("load", myMain, false);

function myMain (evt) {
    // DO YOUR STUFF HERE.
}
在您关心的脚本需要一段时间才能完成的情况下,您将不得不逐个检查某些条件。例如:

window.addEventListener ("load", myMain, false);

function myMain (evt) {
    var jsInitChecktimer = setInterval (checkForJS_Finish, 111);

    function checkForJS_Finish () {
        if (    typeof SOME_GLOBAL_VAR != "undefined"
            ||  document.querySelector ("SOME_INDICATOR_NODE_css_SELECTOR")
        ) {
            clearInterval (jsInitChecktimer);
            // DO YOUR STUFF HERE.
        }
    }
}

1
这是问题所在:我正在查看的页面(https://groups.google.com/forum/?fromgroups=#!searchin/<group-name>/subject:<domain-name>)没有任何可预测的轮询条件;至少,我没有找到过。 - FractalBob
3
它确实有这样的条件,否则你就不能说searchTopic.js加载得太早了。你到底想做什么,如果有的话,在控制台上会得到什么错误信息。...你所说的“答案1和2”是什么意思?这个问题的一个答案被发布者删除了。它没有解决你的问题。 - Brock Adams
@BrockAdams 好的,从那个答案来看,看起来应该使用变异观察器,对吧? - HaveAGuess
1
@HaveAGuess,是的,它们通常可以工作,但在实践中它们经常变得棘手。一个更简单的计时器每次都能正常工作,更加健壮和便携。 - Brock Adams
1
+1对于定时器建议的赞同。在尝试过变异观察器方法后,我可以证明它变得棘手。 - Mitch
显示剩余8条评论

4

2
脚本元素可以被 延迟或异步。或者脚本可以动态加载。或者脚本可以被加载,但其中包含/链接的代码需要一些时间来完成初始化。 - Brock Adams
1
window.onload 等待 async/defer 脚本加载和执行,因此这比在页面底部添加脚本更好。(请参见 W3C 的 HTML API 上的“下载外部脚本必须延迟加载事件。”)等待异步脚本行为(Ajax、setTimeout、事件)的一般问题仍然存在,但这无法以一般方式解决。 - apsillers

-1

你使用 window.load 方法。

function addLoadEvent(a) {
    var b = window.onload;
    "function" != typeof window.onload ? window.onload = a : window.onload = function () {
        b && b(),
            a()
    }
}
function init() {
    alert('init');
}
addLoadEvent(init);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接