简体   繁体   English

Google Chrome扩展程序:页面重新加载后如何立即注入脚本?

[英]Google chrome extension: how to inject script immediately after page reload?

I have a background script that periodically reloads the current tab. 我有一个后台脚本,可以定期重新加载当前选项卡。

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

After each page reload, immediately I want to inject another script. 重新加载每个页面后,我想立即注入另一个脚本。

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

Above is the code I have at the moment. 以上是我目前拥有的代码。 The thing is, it works but it is too slow, because it literally waits after every single image has been loaded. 事实是,它可以运行,但速度太慢,因为它实际上在每个图像加载后都等待。

My goal is to execute the script immediately after DOM load. 我的目标是在DOM加载后立即执行脚本。 Any ideas? 有任何想法吗?

Use a manifest.json content_scripts entry with "run_at": "document_start" 使用manifest.json content_scripts条目和"run_at": "document_start"

Using a manifest.json content_scripts entry with "run_at": "document_start" is the only way that you can guarantee your content script is injected prior to the page existing. 使用带manifest.json content_scripts条目和"run_at": "document_start"确保内容脚本在页面存在之前被注入的唯一方法。 Code injected at this time will find both document.body and document.head will be null . 此时注入的代码将发现document.bodydocument.head均为null

Earliest possible time to inject using tabs.executeScript() 使用tabs.executeScript()最早的注入

The earliest time that works to call tabs.executeScript() is in the webRequest.onHeadersReceived event that fires after the webNavigation.onBeforeNavigate event for the page navigation you are interested in. Using tabs.executeScript() prior to this event may result in your script not being injected in the new page without any reported error. 最早调用tabs.executeScript()是在webRequest.onHeadersReceived事件中,该事件在您感兴趣的页面导航的webNavigation.onBeforeNavigate事件之后触发。在此事件之前使用tabs.executeScript()可能会导致您脚本不会被注入新页面而没有任何报告的错误。 Given the inherent asynchronous nature of the timing between your background script and the process of loading the page, such failures can be intermittent, and will be affected by both OS/system configuration and the exact page that's being loaded. 鉴于后台脚本与页面加载过程之间的时间安排具有固有的异步特性,因此此类故障可能是间歇性的,并且会受到操作系统/系统配置以及正在加载的确切页面的影响。 In fact, my statement that webRequest.onHeadersReceived will work is based on testing, as opposed to verifying in the Chrome source code. 实际上,我声明webRequest.onHeadersReceived可以工作的说法是基于测试,而不是在Chrome源代码中进行验证。 As a result, there may be corner cases which I did not test. 结果,可能存在一些我没有测试过的极端情况。

Injecting at that point consistently works, but the time at which the injection occurs with respect to page loading is somewhat inconsistent. 在这一点上进行注入始终是可行的,但是就页面加载而言注入发生的时间有些不一致。 Sometimes, the document.head and document.body will be null (as will always be the case with a manifest.json content_scripts injection with "run_at":"document_start" ). 有时, document.headdocument.body将为null清单清单的manifest.json content_scripts注入带有"run_at":"document_start"的情况总是如此)。 Other times, the document.head and document.body will contain a valid DOM. 有时, document.headdocument.body将包含有效的DOM。 It does not appear to be possible to get this timed any tighter (ie always have document.head and document.body be null ) due to the background script and the content being in different processes: thus, inherently asynchronous. 由于后台脚本和内容处于不同的进程中,因此似乎无法更严格地计时此时间(即,始终将document.headdocument.bodynull ):因此,它本质上是异步的。

Using webNavigation.onBeforeNavigate and not waiting for at least the associated webRequest.onHeadersReceived event is too early and does not function (content script not injected). 使用webNavigation.onBeforeNavigate没有至少等待关联的webRequest.onHeadersReceived事件为时过早并且无法正常运行(未插入内容脚本)。 In other words, even the associated webRequest.onSendHeaders event is too early. 换句话说,即使关联的webRequest.onSendHeaders事件也为时过早。

Obviously, to get the content script injected that early, you have to specify runAt:'document_start' in your call to tabs.executeScript() . 显然,要尽早注入内容脚本,必须在对tabs.executeScript()调用中指定runAt:'document_start'

To inject just after the DOM exists: webNavigation.onCommitted 在DOM存在后立即注入: webNavigation.onCommitted

If you want something that is easier, and will result in the content script being injected prior to anything in the page other than the main HTML document, then you can just use the webNavigation.onCommitted event for the desired URL to trigger your tabs.executeScript() . 如果您想要更轻松的操作,并且会导致内容脚本先于页面插入,而不是插入主HTML文档,那么您只需使用webNavigation.onCommitted事件获取所需的URL即可触发tabs.executeScript() This will result in the injected content script being loaded immediately after the main HTML document. 这将导致注入的内容脚本在主HTML文档之后立即加载。 Using webNavigation.onCommitted is made easier because it has the ability to specify a filter for your event. 使用webNavigation.onCommitted变得更容易,因为它可以为您的事件指定过滤器。 Thus, you can have your event listener only be called for the URLs you are interested in. 因此,您可以让事件侦听器仅针对您感兴趣的URL进行调用。

The webNavigation.onCommitted event fires after the webRequest.ResponseStarted event for the main HTML page, but before any resources are fetched (ie prior to any webRequest.BeforeRequest events for page resources). 在主HTML页面的webRequest.ResponseStarted事件之后,但在获取任何资源之前(即,在页面资源的任何webRequest.BeforeRequest事件之前),都会触发webNavigation.onCommitted事件。 Interestingly, it does fire after the tabs.onUpdated event that declares a status:'loading' . 有趣的是,它确实在声明status:'loading'tabs.onUpdated事件之后tabs.onUpdated The tabs.onUpdated event with status:'loading' is not a good one to trigger on by itself, because it can fire for other reasons with identical properties, but which don't indicate a page load/reload. status:'loading'tabs.onUpdated事件本身并不是一个很好的触发事件,因为它可以由于其他原因而触发,具有相同的属性,但并不表示页面正在加载/重新加载。

If you only want to tabs.executeScript() upon a page reload 如果只想在重新加载页面时使用tabs.executeScript()

The webNavigation.onCommitted event listener receives a property: transitionType , which will be different values based on the cause of the navigation. webNavigation.onCommitted事件侦听器接收一个属性: transitionType ,根据导航的原因,该属性将是不同的值 One of those values is 'reload' , which you could use to filter for only page reloads. 这些值之一是'reload' ,您可以使用它来过滤仅页面重新加载。

Given that you are interested in page reload, and not loading frames, you will want to make sure that the webNavigation events are for frameId:0 . 考虑到您对页面重新加载感兴趣,而不是对框架加载,您将需要确保webNavigation事件是针对frameId:0

These are the events which occur when you reload a tab by clicking on the "reload this page" button: 这些是通过单击“重新加载此页面”按钮重新加载选项卡时发生的事件:

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}   

Note: This information is based on my own testing. 注意:此信息基于我自己的测试。 I have found no documentation from Google with this level of specificity. 我没有找到Google提供的具有这种特定水平的文档。 The exact timing of what actually works may change in future versions of Chrome. 在以后的Chrome版本中,实际可行的确切时间可能会发生变化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 以编程方式在扩展程序上注入内容脚本(Chrome扩展程序) - Inject content script on extension reload programmatically (chrome extension) 在Google页面上搜索后如何注入脚本 - How to inject a script after searching on google page 在chrome扩展中,如何使用内容脚本注入一个Vue页面 - In chrome extension, how to use content script to inject a Vue page Chrome扩展程序在页面加载之前注入脚本 - Chrome extension inject script before page load setInterval重新加载页面谷歌浏览器扩展程序 - setInterval to reload page google chrome extension 如何在扩展存储数据上有条件地在页面上注入一个 CSS 文件的谷歌浏览器扩展? - How to inject in a google chrome extension a CSS file on a page conditionally on extension storage data? Chrome扩展程序通过严格的CSP将具有动态值的脚本注入页面 - Chrome extension inject script with dynamic value into page with strict CSP Chrome扩展程序内容脚本 - 在页面代码之前注入Javascript - Chrome Extension Content Script - Inject Javascript before page code Chrome 扩展将动态脚本注入 header 并在打开正文标签后 - Chrome Extension to inject dynamic script into header and after opening body tag 在Chrome扩展程序的页面重新加载时执行特定的脚本文件 - Execute a specific script file at reload of the page in chrome extension
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM