【问题标题】:Make my userscript wait for other scripts to load让我的用户脚本等待其他脚本加载
【发布时间】:2011-02-23 15:10:19
【问题描述】:

[编辑:我用一个简单的例子来代替原来的、令人困惑的问题。]

背景

我正在尝试编写一个将在 Chrome 中运行的用户脚本。此脚本需要调用用户脚本之外的 JavaScript 函数 AlertMe() - 此函数是页面的一部分,包含在服务器端动态生成的变量,因此无法重新编写我的用户脚本中的函数。

代码

页面上的脚本 (visit the page):

<script type="text/javascript">
    function AlertMe()
    {
        alert("Function AlertMe was called!");
        // then do stuff with strings that were dynamically generated
        // on the server so that I can't easily rewrite this into the userscript
    }
</script>

我的用户脚本(install it in Chrome):

function tryAlert()
{
    if (typeof AlertMe == "undefined") {
        console.log('AlertMe is undefined.');
        window.setTimeout(tryAlert, 100);
    }
    else {
        AlertMe();
    }
}

tryAlert();

问题

当我尝试简单地调用该函数时,Chrome 的控制台让我知道 AlertMe is not defined。认为这是因为我的用户脚本在所有其他脚本加载之前运行,我使用setTimeout 等待AlertMe 函数被定义。

不幸的是,如果您安装脚本然后访问该页面,您会看到这只会永远输出AlertMe is undefined. 而不会调用该函数。如果你在 Chrome 的控制台中输入typeof AlertMe,它会正确响应"function",那为什么我的用户脚本总是认为AlertMe 未定义?

【问题讨论】:

    标签: javascript google-chrome userscripts


    【解决方案1】:

    您总是可以编写一个小函数来检查该函数是否已加载

    function waitForFnc(){
      if(typeof absearch == "undefined"){
        window.setTimeout(waitForFnc,50);
      }
      else{
        runMyFunction();
      }
    }
    
    function runMyFunction(){
        var urlParams = window.location.search.substring(1).split('&'),
            username = "",
            hscEmailInput = document.getElementById('userfield6'),
            i = 0;
        if (urlParams !== "") {
            for (i = 0; i < urlParams.length; i++) {
                if (urlParams[i].substr(0,4) === "USER") {
                    username = urlParams[i].replace('USER=', '');
                    hscEmailInput.value = username + '@example.com';
                    absearch('&PAGESIZE=1');
                }
            }
        }
    }
    
    waitForFnc();
    

    【讨论】:

    • 我喜欢超时选项,但不确定具体细节。感谢您的示例...我会试一试。
    • 查看我对问题的更新。我的脚本永远认为absearch 是未定义的,即使我可以向控制台询问typeof absearch 并且它正确地告诉我它是一个函数。想法?
    • 好的,我完全重写了这个问题。如果您想自己测试问题,现在可以安装一个简化的测试用例和用户脚本。即使 Chrome 知道该函数已定义,我的用户脚本仍然认为它未定义。我不知道为什么。
    • @Michael Martin-Smucker - 这是一个安全问题,而不是时间问题。请看我的回答。
    • @lwburk,谢谢。 @epascarello,+1,因为您按照最初的措辞回答了我的问题,作为奖励,我在此过程中了解了 window.setTimeout。谢谢:)
    【解决方案2】:

    这不是时间问题。

    您遇到了 Greasemonkey 的安全限制,这会阻止您在页面中执行功能。请参阅我对上一个问题的回答以获得解释和一些安全的解决方法:

    UserScripts & Greasemonkey: calling a website's JavaScript functions

    【讨论】:

    • 非常感谢。因为我只是调用一个函数,所以我使用了定位技巧,它工作得很好。另外,这是一本很好的读物,将来可能会成为非常有用的资源。
    【解决方案3】:

    如果问题确实是您的脚本运行得太早,也许检查并等待 DOM 准备好是解决方案:Relying on DOM readiness to invoke a function (instead of window.onload)

    编辑

    This answer on SO 也可能被证明是有用的。

    【讨论】:

    • DOM 就绪事件意味着:文档已加载。此事件在加载外部资源(如脚本)之前发生。如果您需要在所有资源可用后发生某些事情,则应使用 window.onload 事件。
    • @ithcy 我认为这不是真的。虽然我找不到任何明确的答案 - this 和 this bug report 似乎暗示图像和 CSS 被视为外部资源 - JavaScript 会在出现时被解析。我通过在本地修改和托管this page 并通过限制为 33kbps 的代理访问它在 FF4b11 中对此进行了测试。 DOMContentLoaded 事件仅在我添加的外部 JS 加载后触发。
    • 我的信仰体系——你毁了它! :)
    • @ithcy 如果有帮助,我今天学到了一些东西——我只是在你指出的时候才想到这个:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 2012-07-23
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多