6

几天来我一直在追踪一个错误......然后我意识到这个错误是我。:/

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

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

我会使用 HTML5 规范的 afterscriptexecute,但这并没有在 Chrome 中实现。是否有另一个 API,也许是我可以使用的扩展 API?

4

3 回答 3

8

注意:此方法自 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);

调度时间不是 100% 与原始的相同,但对于大多数情况来说已经足够了。这是(非模拟)事件的时间线:

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/上看到

于 2013-09-04T08:11:43.277 回答
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)定期检查某些函数或变量是否已初始化。

于 2013-08-20T08:41:07.893 回答
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

于 2013-09-04T13:39:51.570 回答