Skip to content
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 termination API "meeting" #455

Closed
annevk opened this issue Jan 14, 2017 · 21 comments
Closed

Fetch termination API "meeting" #455

annevk opened this issue Jan 14, 2017 · 21 comments

Comments

@annevk
Copy link
Member

annevk commented Jan 14, 2017

Please indicate your availability here: http://doodle.com/poll/2iwihhwrw9tx8kkv.

I suggest we use Hangouts, but I'm open to other options.

@delapuente
Copy link

@annevk which timezone?

@annevk
Copy link
Member Author

annevk commented Jan 16, 2017

@delapuente I configured the timezone so it should show up in your local timezone.

@annevk
Copy link
Member Author

annevk commented Jan 21, 2017

The meeting will take place 2017-01-24, 4PM (GMT+01:00). You can still attend, just let me know and I'll share the invite.

Tim O'Ryan, unfortunately I don't have your email address. Please contact me directly so I can add you to the meeting.

@stuartpb
Copy link

stuartpb commented Jan 21, 2017

To be clear, that'd be 3 PM (15:00) UTC, and 7 AM Pacific time? (Also, to spare newcomers some counting: 2017-01-24 is Tuesday.)

@annevk
Copy link
Member Author

annevk commented Jan 21, 2017

Yes, I meant to include this: https://www.timeanddate.com/worldclock/fixedtime.html?msg=Fetch%20termination%20API%20%22meeting%22&iso=20170124T15&am=50. And again, if you want to attend I need to know.

@benjamingr
Copy link
Member

Hey, I would be interested in attending if I'm invited. If I'm not that's also totally fine. I don't want to add in hours so I won't influence the meeting time - let me know when the time is set.

@annevk
Copy link
Member Author

annevk commented Jan 23, 2017

@benjamingr assuming I found the correct email address you got an invite. If not, you need to give me your email address. The time is set as per above.

@benjamingr
Copy link
Member

Thanks! I'll do my best to attend.

@jakearchibald
Copy link
Collaborator

Here's the stuff I'd like to get answers for:

  • Are we looking to control/observe the request, or the response too?
  • Should the return value of fetch() provide means to control/observe the fetch?
  • What's the API?

Use-cases to consider:

  • Controlling fetch(url).then(r => r.json()).
  • Controlling multiple parallel fetches.
  • Controlling a series of fetches.
  • fetchEvent.respondWith(fetch(fetchEvent.request)) - does this get me anything for free? If the page aborts the fetch, will the service worker request/response be aborted?
  • What if a service worker response is made of:
    • An unrelated fetch.
    • Multiple fetches.
    • Cache API match(es).

@benjamingr
Copy link
Member

benjamingr commented Jan 24, 2017

var cancelController;
fetch("/fetch", {
   cancel(cancelFn) { cancelController = cancelFn; }
});
cancelController(); // cancel, returns a promise with true/false

?

@benjamingr
Copy link
Member

var cancelController;
fetch("/fetch", {
   control(controller) { cancelController = controller; }
});
cancelController.cancel(); // cancel, returns a promise with true/false

@benjamingr
Copy link
Member

benjamingr commented Jan 24, 2017

const fetch = fetch("/fetch");
fetch.cancel(); // cancel, returns a promise with true/false
const readonly = fetch.then();

@domenic
Copy link
Member

domenic commented Jan 24, 2017

Other use cases to consider: it would be nice if this mechanism were generic enough to be reused for canceling a stream pipeTo as well.

@jakearchibald
Copy link
Collaborator

jakearchibald commented Jan 24, 2017

Summary

Decided

We're looking for something that cancels the request, but also the response if it's in-flight. This means aborting the body stream if the response body is in-flight.

We're dismissing 'tokens' as an API. Although they work well for cancellation, they don't work well for other modifiers like "priority change".

Adding methods to the return value of fetch() feels too risky. The API gets pretty confusing. The 'species' could be a regular promise:

let fetchling = fetch(url);
// Works…
fetchling.cancel();
fetchling = fetch(url).then(r => r.json());
// Does not work, "cancel" is undefined.
fetchling.cancel();

Although this provides an easy way to return a regular promise, it's pretty confusing. If .then created a controllable fetch promise:

let fetchling = fetch(url).then(r => r.json());
// Works as expected:
fetchling.cancel();

fetchling = fetch(url).then(() => fetch(anotherURL));
// Only cancels the first fetch, which is weird:
fetchling.cancel();

const fetches = Promise.all([
  fetch(url1),
  fetch(url2),
  fetch(url3)
]);
// Does not work, "cancel" is undefined
fetches.cancel();

That said, we're not against controlling methods being added to the return value in future.

We're going to move forward with the revealing-function pattern.

fetch(url, {
  control(controller) {
    // ...
  }
});

Where controller will have methods that alter the in-progress fetch, including canceling & later changing priority.

There will be an component that allows the developer to observe the progress of the fetch. This includes changes to priority, progress, final state (complete, cancelled, error etc). This component will include async getters for current state.

The service worker will receive the "observable" component only.

The observable component should use addEventListener rather than observables. We don't want a TC39 dependency, and true observables are likely to be compatible with addEventListener. We should be careful with the naming of this observer as a result.

Less-decided

What does cancellation looks like? I'm pretty sure this will be a promise rejected with a DOMException with name 'AbortError', but we forgot to cover this in the call. It might already be assumed.

What's the link between the controller and observer? Does the controller object extend the observer? Does the controller have the observer as a property? Are the objects entirely separate?

What's the API for the controller/observer? This is the next step, and there have been some proposals already. Some loose requirements:

  • The observable should be async, so it can exist in a different thread to the fetch.
  • It should be reasonably easy to control multiple fetches in the same way.
  • It should be reasonably easy to observe one fetch, and affect one or more other fetches as a result (this is how a service worker fetch event will obey signals from the thing that invoked the fetch).
  • Aborting an already-complete request shouldn't produce an error, it should be a no-op, but there should be some way to confirm that something was actually aborted. E.g. some deletion APIs return a boolean to signal if anything was actually deleted.

@delapuente
Copy link

delapuente commented Jan 25, 2017

We're going to move forward with the revealing-function pattern.

@jakearchibald does this include passing the future FetchController object to the fetch()? I mean:

const control = new FetchController();
const fetching = fetch(request, { control });

@annevk
Copy link
Member Author

annevk commented Jan 25, 2017

@delapuente we need to hash out the details. If you have specific ideas for how it could all work well together, they're most welcome. A somewhat more detailed proposal by @stuartpb can be found at https://github.com/stuartpb/FetchController-spec.

@jakearchibald
Copy link
Collaborator

@delapuente I updated the original post at #447 with the current state of things.

@stuartpb
Copy link

If there'll be another meeting, I'd like to be included - some time between noon and 7 PM Pacific, if possible (or as close to that as would be feasible).

@stuartpb
Copy link

stuartpb commented Jan 25, 2017

My feedback on the meeting notes:

  • Everything in "Decided" sounds right, though re: "We're going to move forward with the revealing-function pattern." - any thoughts on also allowing FetchControllers to be preconstructed, in the compatible fashion I described in my FetchController-spec?
  • "What does cancellation looks like?" - what you described there is what I've been working with.
  • "What's the link between the controller and observer?" - in the spec I wrote, a FetchObserver is effectively independent of a FetchController (beyond the fact that it is attached to observing the same fetch as the controller controls). A FetchController always contains a FetchObserver, because it shouldn't be possible to end up in a situation where you can act on a fetch whose status you can't read. Note that, as written, a FetchObserver doesn't "belong" to a FetchController so much as it is intrinsically associated with it, due to the dynamics of how a Fetch may be dispatched (there's no way to start a Fetch with a Controller and an Observer that isn't the one attached to that Controller).
  • "The observable should be async, so it can exist in a different thread to the fetch." It's already got an addEventListener, and I think that's quite async enough. If this statement means to assert that multi-threading should imply all mutable properties to be only obtainable through asynchronous accessors, I will state now that I do not concur with that assertion, and can expand on the reasons in a separate issue.
  • "It should be reasonably easy to control multiple fetches in the same way." - Keeping a collection of FetchControllers and performing operations in a coll.forEach(ctl=>{/*...*/}) seems perfectly reasonable to me.
  • Same goes for affecting a fetch as a result of something happening in an observed fetch - observe.addEventListener('abort',e=>coll.forEach(ctl=>ctl.abort())) seems fine to me.
  • "Aborting an already-complete request shouldn't produce an error, it should be a no-op, but there should be some way to confirm that something was actually aborted." - I was thinking this should be an error, but I'm coming around to the argument here that it should be fire-and-report-if-it-did-anything, since we can't well take events out once another thread's put them in the pipe. I'll expand on this in Attempting to modify a fetch after it has completed / aborted / failed #448.

@jakearchibald
Copy link
Collaborator

@stuartpb thanks for the feedback. Just to clarify, when I wrote things like:

What's the link between the controller and observer?

I don't mean "we don't have a clue", I just mean it's yet to be decided. Your proposals have been read, and are being considered.

@jakearchibald
Copy link
Collaborator

Closing this as the meeting happened. I've updated #447 and discussion can continue there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

6 participants