谷歌chrome扩展:如何在页面重新加载后立即注入脚本?

Ano*_*ous 1 javascript google-chrome background-process google-chrome-extension

我有一个后台脚本,定期重新加载当前选项卡.

var code = 'window.location.reload();';
chrome.tabs.executeScript(my_active_tab, {code: code});
Run Code Online (Sandbox Code Playgroud)

每次重新加载页面后,我立即要注入另一个脚本.

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab){
    if (changeInfo.status == 'complete') {
        chrome.tabs.executeScript(tabId, { file: "my_script.js" });
    }
});
Run Code Online (Sandbox Code Playgroud)

以上是我目前的代码.问题是,它工作但速度太慢,因为它在每个图像加载后都会等待.

我的目标是在DOM加载后立即执行脚本.有任何想法吗?

Mak*_*yen 8

使用manifest.json content_scripts条目"run_at": "document_start"

使用manifest.json content_scripts条目"run_at": "document_start"是唯一可以保证 在页面存在之前注入内容脚本的方法.代码注入,此时会发现这两个document.bodydocument.headnull.

尽可能早地注射使用 tabs.executeScript()

最有效的调用时间tabs.executeScript()是在您感兴趣的页面导航事件webRequest.onHeadersReceived之后触发的webNavigation.onBeforeNavigate事件.tabs.executeScript()在此事件之前使用可能导致您的脚本未被注入新页面而没有任何报告错误.鉴于后台脚本与加载页面的过程之间存在固有的异步性质,此类故障可能是间歇性的,并且会受到OS /系统配置和正在加载的确切页面的影响.事实上,我的声明webRequest.onHeadersReceived将基于测试,而不是在Chrome源代码中进行验证.结果,可能存在我没有测试的极端情况.

此时注入始终有效,但注入与页面加载相关的时间有些不一致.有时候,document.head并且document.body将会null(与manifest.json content_scripts注入的情况一样"run_at":"document_start").其他时候,document.head并且document.body将包含一个有效的DOM.由于后台脚本和内容在不同的进程中,似乎不可能使这个时间更紧密(即总是拥有document.headdocument.body成为null):因此,本质上是异步的.

使用webNavigation.onBeforeNavigate不是等待至少相关webRequest.onHeadersReceived事件太早并且不起作用(内容脚本未注入).换句话说,即使是相关webRequest.onSendHeaders事件也为时过早.

显然,要尽早注入内容脚本,您必须runAt:'document_start'在调用中指定tabs.executeScript().

在DOM存在之后注入: webNavigation.onCommitted

如果您想要更容易的东西,并且会导致内容脚本在除主HTML文档之外的页面中的任何内容之前注入,那么您可以使用webNavigation.onCommitted所需URL 的事件来触发您的内容tabs.executeScript().这将导致注入的内容脚本在主HTML文档之后立即加载.使用webNavigation.onCommitted变得更容易,因为它可以为您的事件指定过滤器.因此,您只能为您感兴趣的URL调用事件侦听器.

webNavigation.onCommitted事件webRequest.ResponseStarted在主HTML页面的事件之后触发,但在获取任何资源之前(即在webRequest.BeforeRequest页面资源的任何事件之前).有趣的是,它在tabs.onUpdated声明a 的事件发生后触发status:'loading'.在tabs.onUpdated与事件status:'loading'是不是一个好由自身触发,因为它可以火具有相同属性的其他原因,但并不表明页面加载/重载.

如果您只想重新加载tabs.executeScript()页面

webNavigation.onCommitted事件侦听器接收一个属性:transitionType,这将是不同的值基于导航的原因.其中一个值是'reload',您可以使用它来仅过滤页面重新加载.

鉴于您对页面重新加载感兴趣,而不是加载帧,您需要确保webNavigation事件是为了frameId:0.

这些是通过单击"重新加载此页面"按钮重新加载选项卡时发生的事件:

webNavigation.onBeforeNavigate    ->  arg[0]= {"frameId":0,"parentFrameId":-1,"processId":-1,"tabId":411,"timeStamp":1500401223978.314,"url":"http://www.example.com/"}        
webRequest.onBeforeRequest        ->  arg[0]= {"frameId":0,"method":"GET","parentFrameId":-1,"requestId":"260870","tabId":411,"timeStamp":1500401223979.044,"type":"main_frame","url":"http://www.example.com/"}        
webRequest.onBeforeSendHeaders    ->  arg[0]= {"frameId":0,"method":"GET","parentFrameId":-1,"requestHeaders":[{"name":"Upgrade-Insecure-Requests","value":"1"},{"name":"User-Agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"},{"name":"Accept","value":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"},{"name":"Accept-Encoding","value":"gzip, deflate"},{"name":"Accept-Language","value":"en-US,en;q=0.8"}],"requestId":"260870","tabId":411,"timeStamp":1500401223979.3242,"type":"main_frame","url":"http://www.example.com/"}        
webRequest.onSendHeaders          ->  arg[0]= {"frameId":0,"method":"GET","parentFrameId":-1,"requestHeaders":[{"name":"Upgrade-Insecure-Requests","value":"1"},{"name":"User-Agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"},{"name":"Accept","value":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"},{"name":"Accept-Encoding","value":"gzip, deflate"},{"name":"Accept-Language","value":"en-US,en;q=0.8"}],"requestId":"260870","tabId":411,"timeStamp":1500401223979.538,"type":"main_frame","url":"http://www.example.com/"}        
webRequest.onHeadersReceived      ->  arg[0]= {"frameId":0,"method":"GET","parentFrameId":-1,"requestId":"260870","responseHeaders":[{"name":"Content-Encoding","value":"gzip"},{"name":"Accept-Ranges","value":"bytes"},{"name":"Cache-Control","value":"max-age=604800"},{"name":"Content-Type","value":"text/html"},{"name":"Date","value":"Tue, 18 Jul 2017 18:07:03 GMT"},{"name":"Etag","value":"\"359670651\""},{"name":"Expires","value":"Tue, 25 Jul 2017 18:07:03 GMT"},{"name":"Last-Modified","value":"Fri, 09 Aug 2013 23:54:35 GMT"},{"name":"Server","value":"ECS (rhv/818F)"},{"name":"Vary","value":"Accept-Encoding"},{"name":"X-Cache","value":"HIT"},{"name":"Content-Length","value":"606"}],"statusCode":200,"statusLine":"HTTP/1.1 200 OK","tabId":411,"timeStamp":1500401224072.296,"type":"main_frame","url":"http://www.example.com/"}        
---^^^^^^^^^^^^^^^^^^^^^^^^^-Earliest tabs.executeScript() injection is in the handler for the webRequest.onHeadersReceived event.
webRequest.onResponseStarted      ->  arg[0]= {"frameId":0,"fromCache":false,"ip":"93.184.216.34","method":"GET","parentFrameId":-1,"requestId":"260870","responseHeaders":[{"name":"Content-Encoding","value":"gzip"},{"name":"Accept-Ranges","value":"bytes"},{"name":"Cache-Control","value":"max-age=604800"},{"name":"Content-Type","value":"text/html"},{"name":"Date","value":"Tue, 18 Jul 2017 18:07:03 GMT"},{"name":"Etag","value":"\"359670651\""},{"name":"Expires","value":"Tue, 25 Jul 2017 18:07:03 GMT"},{"name":"Last-Modified","value":"Fri, 09 Aug 2013 23:54:35 GMT"},{"name":"Server","value":"ECS (rhv/818F)"},{"name":"Vary","value":"Accept-Encoding"},{"name":"X-Cache","value":"HIT"},{"name":"Content-Length","value":"606"}],"statusCode":200,"statusLine":"HTTP/1.1 200 OK","tabId":411,"timeStamp":1500401224072.5032,"type":"main_frame","url":"http://www.example.com/"}        
webRequest.onCompleted            ->  arg[0]= {"frameId":0,"fromCache":false,"ip":"93.184.216.34","method":"GET","parentFrameId":-1,"requestId":"260870","responseHeaders":[{"name":"Content-Encoding","value":"gzip"},{"name":"Accept-Ranges","value":"bytes"},{"name":"Cache-Control","value":"max-age=604800"},{"name":"Content-Type","value":"text/html"},{"name":"Date","value":"Tue, 18 Jul 2017 18:07:03 GMT"},{"name":"Etag","value":"\"359670651\""},{"name":"Expires","value":"Tue, 25 Jul 2017 18:07:03 GMT"},{"name":"Last-Modified","value":"Fri, 09 Aug 2013 23:54:35 GMT"},{"name":"Server","value":"ECS (rhv/818F)"},{"name":"Vary","value":"Accept-Encoding"},{"name":"X-Cache","value":"HIT"},{"name":"Content-Length","value":"606"}],"statusCode":200,"statusLine":"HTTP/1.1 200 OK","tabId":411,"timeStamp":1500401224074.0261,"type":"main_frame","url":"http://www.example.com/"}        
tabs.onUpdated                    ->  arg[0]= 411 :: arg[1]= {"status":"loading","url":"http://www.example.com/"} :: arg[2]= {"active":true,"audible":false,"autoDiscardable":true,"discarded":false,"height":902,"highlighted":true,"id":411,"incognito":false,"index":1,"mutedInfo":{"muted":false},"pinned":false,"selected":true,"status":"loading","title":"www.example.com","url":"http://www.example.com/","width":1282,"windowId":10}    
tabs.onZoomChange                 ->  arg[0]= {"newZoomFactor":1,"oldZoomFactor":1,"tabId":411,"zoomSettings":{"mode":"automatic","scope":"per-origin"}}        
webNavigation.onCommitted         ->  arg[0]= {"frameId":0,"processId":107,"tabId":411,"timeStamp":1500401224079.4019,"transitionQualifiers":[],"transitionType":"reload","url":"http://www.example.com/"}
--->>Here is where you can tell it's a reload --------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^
history.onVisited                 ->  arg[0]= {"id":"42","lastVisitTime":1500401224077.579,"title":"Example Domain","typedCount":1,"url":"http://www.example.com/","visitCount":12}        
tabs.onUpdated                    ->  arg[0]= 411 :: arg[1]= {"title":"Example Domain"} :: arg[2]= {"active":true,"audible":false,"autoDiscardable":true,"discarded":false,"height":902,"highlighted":true,"id":411,"incognito":false,"index":1,"mutedInfo":{"muted":false},"pinned":false,"selected":true,"status":"loading","title":"Example Domain","url":"http://www.example.com/","width":1282,"windowId":10}    
webNavigation.onDOMContentLoaded  ->  arg[0]= {"frameId":0,"processId":107,"tabId":411,"timeStamp":1500401224093.404,"url":"http://www.example.com/"}        
webNavigation.onCompleted         ->  arg[0]= {"frameId":0,"processId":107,"tabId":411,"timeStamp":1500401224094.768,"url":"http://www.example.com/"}        
tabs.onUpdated                    ->  arg[0]= 411 :: arg[1]= {"status":"complete"} :: arg[2]= {"active":true,"audible":false,"autoDiscardable":true,"discarded":false,"height":902,"highlighted":true,"id":411,"incognito":false,"index":1,"mutedInfo":{"muted":false},"pinned":false,"selected":true,"status":"complete","title":"Example Domain","url":"http://www.example.com/","width":1282,"windowId":10}   
Run Code Online (Sandbox Code Playgroud)

注意:此信息基于我自己的测试.我没有找到Google提供的具有此级别特异性的文档.实际工作的确切时间可能会在未来版本的Chrome中发生变化.