-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: add new browser.tabs.waitForTab(tabId: number)
that will wait for tab to load
#591
Comments
This is a common issue: When is a tab ready to be messaged? The best solution at this point appears to be: I think a better solution for messaging could be: const tab = await browser.tabs.create({url: '/quetions.html'});
const response = await browser.tabs.sendMessage(
tab.id,
{type: 'ask_user_for_something'},
{waitForListener: true} // 👈
); This way the message would wait indefinitely until the content script called Messaging as a whole is painful and I think it needs to be reevaluated. The worst offender is |
It should be optional and we should be able to specify the timing e.g.
Just waiting for a listener may be unreliable with chrome.tabs.update because it may send to the current contents of the tab before it is navigated as the browser doesn't destroy it until the new URL's response is received. It could be something like |
Some considerations that were raised during today's discussion include:
|
I'll raise a few questions:
|
I would be more supportive of having a |
@fregante regarding the Promise VS event, using Promise allows caller to await the tab creation operation (page load) and continue working with the tab without loosing the context, for example sending it work/command/request/query. This will make the execution flow easy to reason about (see my original comment for an example). I would say the Promise should resolve after all content scripts are executed - that is, for the specific load event the API is targeting. I can imagine the default could be That should fix all race conditions since in both cases you would be sure that the page code was executed so all top level registered handlers are ready. This includes extension pages, content script powered pages and normal websites. And ideally also popup and toolbar, although I'm not sure now how to target those |
Maybe
|
I like the Proposal for
|
@tophf That was the intention for all states. If you have a content script at any run_at mode this function can be used to wait for it to have listeners registered (including document_idle). |
Ah, sorry, I see it's already specifically mentioned. But maybe you could specify what happens if there are no content scripts. |
This proposal likely could be polyfilled by using That would be a good way to test this design out and guide any further changes needed. I likely won't have time to write that polyfill, but anyone else is welcome to take a crack at it! The only complications I see with a polyfill are:
|
Yes, for the content script case, which is arguably the most popular one, but waitForLoad may be useful even without host access and a content script, in which case it can be polyfilled by using chrome.webNavigation.onCommitted (or chrome.tabs.onUpdated) + tabs.onRemoved + tabs.onReplaced and that won't have the problem of targeting the tab. |
@xeenon great idea with the const newTab = await browser.tabs.duplicate(thisTabId);
await browser.tabs.waitForLoad({tabId: newTab.id});
await browser.tabs.sendMessage(newTab.id, {type: 'openSearch'}); And although it works in Firefox where you can register content scripts even for extension pages, it won't work in Chrome where you can't. const scriptId = 'browser.tabs.waitForLoad_' + JSON.stringify(target);
await browser.scripting.registerContentScripts([{
id: scriptId,
matches: [
'<all_urls>',
browser.runtime.getURL('') + '*',
],
js: ['/wait_for_load.content_script.js'],
runAt: 'document_end',
}]); It will complain about: |
@Juraj-Masiar Bummer! |
I'm not in favor of this on the Chromium side. There are two main reasons: There isn't a single definition of what "waitForTab()" should do.In conversations, we've covered all kinds of different possible events:
In addition, there's other handling that raises questions, e.g.
I think @xeenon 's comment here does a good job of highlighting some of the complexities here. We could choose some of these as defaults, but likely any single configuration of these we choose wouldn't work for the majority of extension developers. Additionally, I don't think adding individual toggles for all of these at the browser level doesn't scale well and brings much more complexity to the platform. This is already doable with existing extension APIs.One can fairly trivially create a listener that listens for the tab to be loaded -- for the definition of "loaded" that meets their needs. I do agree that this is a common pain point that many extension developers face; however, rather than solving this at the platform level, I think this is a good opportunity for library support. A library could provide a variety of all these different functionalities in a relatively straightforward way, including providing developers configuration options for listening to the event in the way they want to. I think library support is something that we've historically had a dearth of in the extensions space, but I don't think that's a reason to add all these components to the platform. Rather, I'd like to see us encouraging this library development (and, ideally, as browser vendors, we can perhaps even maintain a few common libraries -- I think this would be a great candidate for that). I agree with the motivation behind this, but don't think it's something that needs to be, or should be, solved at the platform level. |
The issue is always the same, but every time slightly different:
tabId
.And this is one huge race condition, because some API calls in some browsers will fail if the page is not loaded (example, example).
Existing workarounds are complex:
tabs.onUpdated
to watch for status "complete" event - again, a lot of code needed and was very buggy in the past (for example "complete" fired twice in some cases).webNavigation.onCompleted
is similarly complex plus requireswebNavigation
permissionThe proposed,
browser.tabs.waitForTab
API would solve all this in one line, example:There could be a second optional parameter in this API that would specify, whether to await the
DOMContentLoaded
orload
event. WithDOMContentLoaded
being a default.And if the tab is not in the "loading" state, it would resolve right way.
Alternative solution 1:
Updating specification for the
tabs.create
,tabs.update
,windows.create
and similar API, to require them to resolve the returned promise only after the DOMContentLoaded event.Alternative solution 2:
Updating specification for
scripting.executeScript
,tabs.sendMessage
and similar, to require them to await tab getting ready before executing them.The text was updated successfully, but these errors were encountered: