4

我一直在追踪一个错误数天...然后我意识到错误是我。 :/如何检测脚本是否被加载*和*在Chrome扩展中执行?

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

我现在唯一能想到的解决方案是在执行之前修改JS被加载的内容。但它使我的胃转向。而且bfcache会带来更大的破坏,所以也不是一个好的解决方案。

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

+0

顺便说一句,不能使用HTML5加载事件,它是一个简单的事件,因此不会冒泡。 – sroussey

+0

您可以看到何时使用此解包扩展执行各种事件:https://github.com/simov/事件记录器,它不是直接解决你的问题,但它可能帮助你找出你应该听的事件。您还可以单击控制台中的对象来查看每个步骤中的数据。 – simo

回答

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/现场看到

+0

我不知道以前是一个冒泡事件(加载不是,这是一个令人难以置信的痛苦)。我认为这会起作用!巧妙,谢谢! – sroussey

+0

@sroussey FYI,'beforeload'可能会从未来的Chrome版本中删除(请参阅http://crbug.com/333318)。 –

0

我不熟悉Chrome扩展(仅浏览器JavaScript),但我认为你不幸必须编辑加载的JS,以便在执行时调用你选择的函数,如果你想做这很好。这是什么谷歌确实为异步加载其地图的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递归函数)定期检查是否一些函数或变量被初始化。

+0

我不能使用任何一种技术。我不知道正在加载的文件,所以我不知道要找什么。并且超时将不起作用,因为它不能保证通过代码在两个脚本标记的结果之间运行JS运行。 – sroussey

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'); 
     } 
    } 
}); 

如果触发假,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

+0

我正在开发一个扩展,因此不会去创建页面,否则会有一整套工具可供我使用。像这个。 :) – sroussey

相关问题