Re: [whatwg/fetch] Deferred fetching (PR #1647)

@fergald commented on this pull request.



> @@ -8449,6 +8597,60 @@ with a <var>promise</var>, <var>request</var>, <var>responseObject</var>, and an
 </div>
 
 
+<h3 id=fetch-later-method>FetchLater method</h3>
+
+<pre class=idl>
+
+dictionary DeferredRequestInit : RequestInit {
+  DOMHighResTimeStamp backgroundTimeout;
+};
+
+partial interface mixin WindowOrWorkerGlobalScope {
+  [NewObject] Promise&lt;Response> fetchLater(RequestInfo input, optional DeferredRequestInit init = {});

Are we including the Response? I thought weren't.

> @@ -8449,6 +8597,60 @@ with a <var>promise</var>, <var>request</var>, <var>responseObject</var>, and an
 </div>
 
 
+<h3 id=fetch-later-method>FetchLater method</h3>
+
+<pre class=idl>
+
+dictionary DeferredRequestInit : RequestInit {
+  DOMHighResTimeStamp backgroundTimeout;
+};
+
+partial interface mixin WindowOrWorkerGlobalScope {
+  [NewObject] Promise&lt;Response> fetchLater(RequestInfo input, optional DeferredRequestInit init = {});

I think the Promise model has an unavoidable race caused by getting JS involved in delivering this state change information.

Here's the most direct way I can think of to trigger the issue

```js
let completed = false;

fetchLater(...).then(() => {completed = true});

addEventListener("pagehide", () => {
  // This task will run first-thing after `pageshow`
  setTimeout(() => {
    if (!completed) {
      doSomething();
    } 
  }, 0);
});
```

Now let's say the fetch occurs while in BFCache. The first task to run on restore from BFCache will see complete as still `false` and will call `doSomething` incorrectly.

Even if we somehow make the tasks that run the promise resolves special so that they run first, you can recreate the same problem using 2 `fetchLater`s. One of the resolve callbacks must run first and would see the wrong value for the `completed` of the other fetch.

It might also be that any `pageshow` event handler will run before these callbacks. I can't find a clear answer to that. Document reactivation is [here](https://html.spec.whatwg.org/multipage/browsing-the-web.html#document-state:reactivate-a-document) but I'm not sure where the task queue is unfrozen.

This race was avoided in the original design because `isPending()` had access to the true state. It was all handled in native code which is allowed to execute while in BFCache - the timer expires, the renderer tells the browser to send and updates the pending state.

I think the only way to avoid this issue is to have an object that gives access to the state and update that object outside of JS.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/fetch/pull/1647#pullrequestreview-1432133879
You are receiving this because you are subscribed to this thread.

Message ID: <whatwg/fetch/pull/1647/review/1432133879@github.com>

Received on Thursday, 18 May 2023 07:28:07 UTC