我已经追踪了几天的bug ...然后我意识到这个bug就是我。 :/
我一直在使用webRequest.onComplete,过滤脚本。我的错误是我在加载和执行的脚本之间建立了错误的关联。 get以不同于它们执行的顺序加载,因此事件的时间顺序不是我需要的顺序。我需要在某些脚本之间注入,所以我需要在文件执行之后和之前发生事件下一个。
目前我能想到的唯一解决方案是在执行之前更改正在加载的JS。但它让我的胃转了。 bfcache会造成更大的破坏,所以也不是一个好的解决方案。
我会使用HTML5规范的afterscriptexecute,但这不是在Chrome中实现的。是否有其他API,也许是我可以使用的扩展API?
答案 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';
现场观看
答案 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