-
Notifications
You must be signed in to change notification settings - Fork 2k
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
UI: Replace the adapter cancellation methods with a cancellation token system #5721
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey 👋
I really like the sound of this approach. I left a couple of mainly stylistic/design comments. In a similar vein, if these are called 'cancellation tokens' should you cancel
them not abort
them? You could almost make these CancellationTokens 'not about xhr', probably going too far there though.
None of those comments are important, its mainly just words / bikeshedding but I thought I'd mention in case you like it.
I might have another look at this later, but all looks good!
Oh, I've been looking to see if this effects the connection throttling thing (the 6 connection browser limit thing) but I can't remember where you deal with that, can you remind me where that is?
Thanks,
John
ui/app/utils/classes/xhr-token.js
Outdated
export default class XHRToken { | ||
get xhr() { | ||
return this._xhr; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if you need to expose xhr
as a property here? I've only glanced at the entire changeset for now, but thinking about what you are doing here, I'm guessing you probably want to make the underlying XHR private? No biggie, just incase you want to clean that up a touch. (obvs the this.xhr.abort()
below would need to use the _xhr
instead)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's probably not necessary, just seemed like the right thing at the time. However, even making the xhr read-only means you could do something like assign the xhr somewhere else and abort it outside of the token, which is not ideal.
ui/app/adapters/watchable.js
Outdated
@@ -86,7 +62,7 @@ export default ApplicationAdapter.extend({ | |||
}); | |||
}, | |||
|
|||
reloadRelationship(model, relationshipName, watch = false) { | |||
reloadRelationship(model, relationshipName, watch = false, cancellationToken) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually I think its a good idea to put all defaulting arguments to the right hand side, so either:
reloadRelationship(model, relationshipName, cancellationToken, watch = false) {
or
reloadRelationship(model, relationshipName, watch = false, cancellationToken = {}) {
// or
reloadRelationship(model, relationshipName, watch = false, cancellationToken = new Token()) {
not sure what exactly here, and completely understand this is an improvement so you might be avoiding the argument ordering refactor here.
I 'think' you generally will be providing cancellationTokens so the former possibly makes most sense?
reloadRelationship(model, relationshipName, cancellationToken, watch = false) {
Again no biggie, and I'm thinking you might be leaving this out to avoid the ordering refactor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha, this was just me being hasty on a Thursday evening 😅 I think I'll change this to make watch and cancellationToken both options, similar to how adapterOptions
work.
reloadRelationship(model, relationshipName, options = { cancellationToken: null, watch: false })
Hey @DingoEatingFuzz, this looks good, but I did have one general comment. Have you thought about what it looks like when cutting jQuery out of the equation? Fetch's |
@johncowen, thank you for the review! To answer your question about the six connection limit, that happens on page transitions. From the |
@meirish, yes, I did briefly think about the post-jquery world. AbortControllers are awesome, but they're still quite new and not supported in IE11. As you mentioned, AbortControllers follow a similar token pattern. In fact I may be able to replace the XHRToken class with AbortController, but this is all moot for the time being. I suspect that even after removing jquery, Nomad will be using XHRs. In which case the adapter will have to change, but everything else will remain the same. |
913888f
to
3c1de2d
Compare
Okay, I ended up standardizing on Abort instead of Cancel, since that's what both XHR and fetch (ala AbortController) use. |
I'm going to lock this pull request because it has been closed for 120 days ⏳. This helps our maintainers find and focus on the active contributions. |
This replaces the way that XHR cancellation happens throughout the app.
Before
Cancellation was handled by adapters. Adapters would track all the XHRs and exposed methods that took adapter-like arguments (model name and ID). The cancel method would then look up the XHRs in the registry and abort them.
This had one major issue: there was no discerning between two requests to an identical endpoint.
This may seem like an edge case, but it's oddly easy to end up in this situation. If Page 1 is watching record A and then the app transitioning to Page 2 that tries to load record A in the model hook, the order of events goes:
After
XHRTokens are created at the point where watch requests are made. The XHRToken is more or less an empty object. The XHRToken is passed along to the adapter watch/find methods. The Adapter assigns the XHR to the token. Now the find/watch callsite has a reference to the XHR and can be responsible for cancellation.
Now cancellation is per request rather than per url and our problems go away.
This approach takes inspiration from axios.