-
Notifications
You must be signed in to change notification settings - Fork 9
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
Fetch-based design #70
Comments
What you suggest is similar to an alternative approach we previously proposed: adding I think this is a question about to what level of abstraction we should provide. One reason for this previous proposal ( |
Yea I think the alternative approach works better, with handling background-timing and the rest of the semantics (including the visibility-related things) in userland. We can provide a "best practices" pure JS wrapper that looks like the |
One more question to answer is: how can developers know that a pending fetch was or wasn't yet sent, when they have more data to potentially append to it? What we could do is resolve the Fetch promise when the request is starting to be sent (rather than when a response arrives), and resolve it without a response. There may be better alternatives to get that signal. Another question would be around the ergonomics of aborting a |
Ergonomics-wise I think it's fairly simple but let's see what we come up with. Is the response promise not enough for understanding if your beacon was sent? Isn't it actually better, as in, if there was a network issue or 500 error or what not you can still re-send it? If we do need a resolve-on-request, I think this should have its own call (or |
So something like let hasBeenSent = false;
let abort = new AbortController();
fetch(...).then(() => {hasBeenSent = true;};
function updateData(data)
if (!hasBeenSent) {
abort.abort();
}
hasBeenSent = false;
fetch(...).then(() => {hasBeenSent = true;};
} We have to worry about the timing of microtasks. Thinking about Chrome's impl, as long as the browser sending is blocked on "go ahead" from the renderer (when it's still alive) then we can post that microtask when the renderer gives that "go ahead". As long as it runs before any other JS, we're OK. If some any other JS could sneak in before it runs then it will see I'm not familiar enough with JS microtask queueing to know what happens if e.g. we have a a queued JS task and then we post a microtask before that task runs. Does the microtask run immediately or will it run at the end of the already queued JS task? |
Imagining userland code that uses it would look something like this:
|
Posted microtasks always run before queued tasks. |
Waiting for the response promise to resolve would be racy, and can lead to wasted client and server resources. A few constraints that the original design had in mind:
If we waited for the response, we run a risk of aborting an in-flight request, either wasting resources if it waas terminated halfway through, or reporting the same data twice, if it we aborted after the response was sent from the server.
I think this was one of the considerations that lead to the PendingBeacon design. An alternative is to have the |
... or it can still resolve if there was a response. why not? |
Nice! (although, if we're using an event there may be a task queueing race? If so, being able to sync check SentSignal would solve that, I think) |
Event doesn't imply anything about tasks. But also |
That's fair.. |
Microtasks posted from a JS task will run before other queued JS tasks but sending of a beacon in Chrome is an IPC from the browser to the renderer to say "hey I want to send this, if it's not already cancelled, mark it sent and tell me I can go ahead". So I guess as long as that posts an empty JS tasks that then runs this microtask and as long as that whole thing happens before any other JS tasks that happened to be enqueued already, we're ok. I don't know if this is simply an implementation problem or if it is impossible spec-wise to say "here's a micro task, it must jump the queue on anything else that's already queued". I don't think the spec has any concept of non-JS tasks, so there is no JS task for this microtask to run after. |
You can't "queue a microtask" via IPC. It would have to be a regular task that resolves a promise. |
OK, so then implementation-wise, in that IPC we would want to synchronously run an empty JS task with this microtask. This seems doable at least. |
Offline discussion today: PendingBeacon Size LimitFetch Spec enforces a 64KB size limit for Scenario 1: if user makes a X (>64KB) size PendingBeacon request, it should fail, throwing Scenario 2: if user makes a X (<=64KB) size PendingBeacon request, it should be queued to send. If after queuing, the total excceeds the 64KB limit, the browser flushes the queues earlier than the time of page destruction. Can enabling BackgroundFetch permission allows to bypass this limit?
|
@noamr is right. The Motivation section from the explainer already makes it clear that we want an API to |
What I'm saying is that in a large number of cases you won't know whether they are transmitted via this kind of feature as the page will not be in the back-forward cache. @mingyc I don't see how that relates to determining success (and only in the back-forward cache case)? |
Correct. But for those cases it's unnecessary as they would be transmitted when unloaded. |
The goal is not to determine success or failure. One use case is a beacon that accumulates data. You have some new data. If the beacon has not been sent, you cancel it and create a new one with the accumulated data. If the beacon has been sent you start a new one with this new data as the first piece of accumulated data. You need a sent/not-sent signal in order to make decisions about beacons when they can spontaneously be sent. |
Thanks for your patience in explaining this additional wrinkle. I discussed this with colleagues and we're supportive of addressing it. Here's an API that would make sense to us: a |
Thanks for seriously discusses the use cases @annevk, I'm supportive of this solution. IMO it can also be a |
Yeah, that's fair. Probably best to stick the most minimal thing (i.e., your suggestion) as that can also be extended in much the same way. |
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
See initial fetch PR: whatwg/fetch#1647 |
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
The design presented today was better than the get-and-post-only design previously proposed, but still not quite as good as I think it can be. I think we still need to think less about designing around the current use case and ask ourselves "what is the minimal addition to fetch that would allow me to do what I need to do?" and I think the answer is just some kind of signal to send now and two new values in the RequestInit dictionary: background timeout seconds and a boolean value saying this is deferred until unload. If you want to change the URL or content, you abort the fetch and start a new one.
The text was updated successfully, but these errors were encountered: