[英]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?
有任何想法吗?
content_scripts
entry with "run_at": "document_start"
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.body
和document.head
均为null
。
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.head
和document.body
将为null
( 清单清单的manifest.json content_scripts
注入带有"run_at":"document_start"
的情况总是如此)。 Other times, the document.head
and document.body
will contain a valid DOM. 有时,
document.head
和document.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.head
和document.body
为null
):因此,它本质上是异步的。
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'
。
webNavigation.onCommitted
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
事件本身并不是一个很好的触发事件,因为它可以由于其他原因而触发,具有相同的属性,但并不表示页面正在加载/重新加载。
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.