如何检测脚本是否已加载*和*在chrome扩展中执行?

时间:2013-08-19 21:54:27

标签: google-chrome google-chrome-extension google-chrome-devtools

我已经追踪了几天的bug ...然后我意识到这个bug就是我。 :/

我一直在使用webRequest.onComplete,过滤脚本。我的错误是我在加载和执行的脚本之间建立了错误的关联。 get以不同于它们执行的顺序加载,因此事件的时间顺序不是我需要的顺序。我需要在某些脚本之间注入,所以我需要在文件执行之后和之前发生事件下一个。

目前我能想到的唯一解决方案是在执行之前更改正在加载的JS。但它让我的胃转了。 bfcache会造成更大的破坏,所以也不是一个好的解决方案。

我会使用HTML5规范的afterscriptexecute,但这不是在Chrome中实现的。是否有其他API,也许是我可以使用的扩展API?

3 个答案:

答案 0 :(得分:7)

注意:此方法no longer works as of Chrome 36。没有直接的选择。

注意:以下答案仅适用于外部脚本,即加载<script src>的脚本。

在Chrome(和Safari)中,“beforeload”事件在加载资源之前触发。此事件允许用户阻止资源,因此永远不会获取脚本。在这种情况下,您可以确定加载的资源是否是脚本,并检查是否要执行某些操作

此事件可用于模拟beforescriptexecute / afterscriptexecute

document.addEventListener('beforeload', function(event) {
    var target = event.target;
    if (target.nodeName.toUpperCase() !== 'SCRIPT') return;
    var dispatchEvent = function(name, bubbles, cancelable) {
        var evt = new CustomEvent(name, {
            bubbles: bubbles,
            cancelable: cancelable
        });
        target.dispatchEvent(evt);
        if (evt.defaultPrevented) {
            event.preventDefault();
        }
    };
    var onload = function() {
        cleanup();
        dispatchEvent('afterscriptexecute', true, false);
    };
    var cleanup = function() {
        target.removeEventListener('load', onload, true);
        target.removeEventListener('error', cleanup, true);
    }
    target.addEventListener('error', cleanup, true);
    target.addEventListener('load', onload, true);

    dispatchEvent('beforescriptexecute', true, true);
}, true);

发货时间与原始发货时间不完全相同,但对大多数情况来说已足够。这是(非模拟)事件的时间线:

beforeload             Before the network request is started
beforescriptexecute    Before a script executes
afterscriptexecute     After a script executes
onload                 After the script has executed

这是一种简单的方法,可以看到事件按预期工作:

window.addEventListener('afterscriptexecute', function() {
    alert(window.x);
});
document.head.appendChild(document.createElement('script')).src = 'data:,x=1';
document.head.appendChild(document.createElement('script')).src = 'data:,x=2';

该演示可在http://jsfiddle.net/sDaZt/

现场观看

答案 1 :(得分:0)

我不熟悉Chrome扩展程序(仅限浏览器javascript),但我认为您将不得不编辑已加载的JS,以便在执行时调用您选择的函数,如果您想这样做很好。这就是Google为异步加载Maps Javascript文件而做的事情:

function loadScript() {
  var script = document.createElement("script");
  script.type = "text/javascript";
  script.src = "http://maps.googleapis.com/maps/api/js?sensor=false&callback=executed";
  document.body.appendChild(script);
}

function executed() {
  /* Google maps has finished loading, do awesome things ! */
}

如果你真的不想编辑加载的JS文件,你可以使用setInterval(或带setTimeout的递归函数)定期检查是否初始化了某些函数或变量。

答案 2 :(得分:0)

您是否尝试使用Modernizr.js加载脚本?

我遇到了类似的问题,脚本加载的时间导致了冲突。我使用了Modernizr.js,默认包含库yepnope.js。下面是我有条件加载的一些脚本的示例。您可以包含一个测试子句,或者只是按照您喜欢的顺序加载它们,并保证它们将按照您回调的顺序加载和执行。

以下是条件子句的示例:

Modernizr.load({
    test: false, //Or whatever else you'd like. Can be conditional, or not so conditional
    yep: {
        'script1': 'MyJavascriptLibrary1.js'
    },
    nope: {
        'script2': 'MyJavascriptLibrary2.js',
        'script3': 'MyJavascriptLibrary3.js'
    },
    callback: {
        'script1': function (url, result, key) {
            console.log('MyJavascriptLibrary1.js loaded'); //will not load in this example
        },
        'script2': function (url, result, key) {
            console.log('MyJavascriptLibrary2.js loaded first');
        },
        'script3': function (url, result, key) {
            console.log('MyJavascriptLibrary3.js loaded second');
        }
    }
});

如果触发false,MyJavascriptLibrary2.js和MyJavascriptLibrary3.js将以适当的顺序加载,无论哪些元素影响它们的正常行为(文件大小,连接速度等)。在这些回调中,您可以按照您希望的顺序触发其他javascript。例如:

'script2': function (url, result, key) {

            alert('anything in here will fire before MyJavascriptLibrary3.js executes');
        },

请注意,这可以在没有Modernizr.load({...

)的情况下完成

但只使用yepnope({...

有关更多文档,请查看yepnope.js API