javascript - 谷歌浏览器扩展 : how to inject script immediately after page reload?

标签 javascript google-chrome google-chrome-extension background-process

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

var code = 'window.location.reload();';
chrome.tabs.executeScript(my_active_tab, {code: code});

每次重新加载页面后,我都想立即注入(inject)另一个脚本。
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab){
    if (changeInfo.status == 'complete') {
        chrome.tabs.executeScript(tabId, { file: "my_script.js" });
    }
});

以上是我目前的代码。问题是,它可以工作,但是太慢了,因为它实际上是在加载每个图像后等待。

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

最佳答案

使用 manifest.json content_scripts带有 "run_at": "document_start" 的条目
使用 manifest.json content_scripts带有 "run_at": "document_start" 的条目是您可以保证在页面存在之前注入(inject)内容脚本的唯一方法。此时注入(inject)的代码会找到document.bodydocument.head将是 null .
使用 tabs.executeScript() 尽早注入(inject)
最早工作时间调用 tabs.executeScript() webRequest.onHeadersReceived webNavigation.onBeforeNavigate 之后触发的事件您感兴趣的页面导航事件。使用 tabs.executeScript()在此事件之前可能会导致您的脚本没有被注入(inject)新页面而没有任何报告错误。鉴于后台脚本和加载页面过程之间的时间固有的异步性质,此类故障可能是间歇性的,并且会受到操作系统/系统配置和正在加载的确切页面的影响。事实上,我的声明 webRequest.onHeadersReceived将工作基于测试,而不是在 Chrome 源代码中进行验证。因此,可能存在我没有测试的极端情况。
在该点注入(inject)始终有效,但是相对于页面加载发生注入(inject)的时间有些不一致。有时,document.headdocument.body将是 null (与 manifest.json content_scripts 注入(inject) "run_at":"document_start" 的情况一样)。其他时候,document.headdocument.body将包含一个有效的 DOM。由于后台脚本和内容处于不同的进程中,因此似乎不可能更紧地安排这个时间(即总是有 document.headdocument.bodynull ):因此,本质上是异步的。
使用 webNavigation.onBeforeNavigate并且至少不等待相关的 webRequest.onHeadersReceived事件太早且不起作用(未注入(inject)内容脚本)。换句话说,即使是关联的 webRequest.onSendHeaders 事件太早了。
显然,要尽早注入(inject)内容脚本,您必须指定 runAt:'document_start' 在您调用 tabs.executeScript() .
在 DOM 存在后立即注入(inject): webNavigation.onCommitted
如果你想要一些更简单的东西,并且会导致内容脚本在页面中除主 HTML 文档之外的任何内容之前被注入(inject),那么你可以使用 webNavigation.onCommitted 所需 URL 的事件以触发您的 tabs.executeScript() .这将导致在主 HTML 文档之后立即加载注入(inject)的内容脚本。使用 webNavigation.onCommitted变得更容易,因为它能够为您的事件指定过滤器。因此,您可以只为您感兴趣的 URL 调用事件监听器。webNavigation.onCommitted事件在 webRequest.ResponseStarted 之后触发主 HTML 页面的事件,但在获取任何资源之前(即在任何页面资源的 webRequest.BeforeRequest 事件之前)。有趣的是,它确实会在 tabs.onUpdated 之后触发。声明 status:'loading' 的事件. tabs.onUpdated status:'loading' 的事件单独触发不是一个好方法,因为它可以因其他原因而触发,具有相同的属性,但并不表示页面加载/重新加载。
如果你只想tabs.executeScript()在页面重新加载时webNavigation.onCommitted事件监听器接收到一个属性: transitionType ,这将是 different values根据导航的原因。这些值之一是 '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}   

注意:此信息基于我自己的测试。我没有从谷歌找到具有这种特殊性的文档。实际工作的确切时间可能会在 Chrome 的 future 版本中发生变化。

关于javascript - 谷歌浏览器扩展 : how to inject script immediately after page reload?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42151342/

相关文章:

javascript - Chrome 扩展消息传递 : Unchecked runtime. lastError : Could not establish connection. 接收端不存在

JQuery 无法在我的 Google Chrome 扩展、内容脚本中运行?

javascript - asp.net mvc 中的 javascript 变量出现问题

javascript - 当前浏览器中剪贴板的最大大小

javascript - 为什么当我单击下一个或上一个时,完整日历 jquery 插件无法按预期工作?

api - Spotify 播放按钮不起作用 - 在最近的 Chrome 中仅播放预览

javascript - Chrome 富通知是否已弃用

android - Meteor 应用程序在 Android 上的 chrome 浏览器中打开 URL

javascript - 在 Javascript 中遍历 JSON 字符串的最快方法

javascript - Chrome 扩展程序中从内容脚本到后台页面的消息传递