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

相關問題