-
Notifications
You must be signed in to change notification settings - Fork 50k
[scheduler] 3/n Use a linked list instead of map and queue for callback storage #12893
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
[scheduler] 3/n Use a linked list instead of map and queue for callback storage #12893
Conversation
acdlite
left a comment
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.
Left some comments, none of them are too serious but it'd be cool to discuss them before merging.
| |}; | ||
|
|
||
| export type CallbackIdType = any; | ||
|
|
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.
Why is this any instead of CallbackConfigType?
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.
Let's discuss this in person - the tldr is that we sometimes want the 'callbackIdType' to be a number, sometimes the CallbackConfigType, sometimes something else.
| headOfPendingCallbacksLinkedList.previousCallbackConfig = null; | ||
| } | ||
| if (tailOfPendingCallbacksLinkedList === latestCallbackConfig) { | ||
| tailOfPendingCallbacksLinkedList = null; |
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.
This the same as the else block of the previous if statement. If there's no next callback in the list, then the list must be empty now.
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.
That's true - if it's more clear will write it that way.
| // move head of list to next callback | ||
| headOfPendingCallbacksLinkedList = | ||
| latestCallbackConfig.nextCallbackConfig; | ||
| if (headOfPendingCallbacksLinkedList) { |
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.
Make sure we always explicitly compare to null
| */ | ||
| const previousCallbackConfig = callbackConfig.previousCallbackConfig; | ||
| const nextCallbackConfig = callbackConfig.nextCallbackConfig; | ||
| if (previousCallbackConfig) { |
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.
Same here, compare against null
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.
I find this much easier to follow using nested if statements. The reason I prefer that style is it makes it easier to avoid redundant type checks.
if (callback === head) {
if (callback === tail) {
// List is now empty
head = tail = null;
} else {
// Remove from start of list
head = callback.next;
// (Flow will complain that `head` could be null)
head.previous = null;
}
} else if (callback === tail) {
// Remove from end of list
tail = callback.previous;
// (Flow will complain that `tail` could be null)
tail.next = null;
} else {
// Remove from middle of list
const previous = callback.previous;
const next = callback.next;
// (Flow will complain that `previous` and `next` could be null)
previous.next = next;
next.previous = previous;
}But it seems like maybe the redundant checks are necessary to satisfy Flow? That's a shame.
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.
I can try to rewrite it this way, think we can still make Flow happy.
Might be ok with concise > clear in this particular module, but for now let me try the more clear way.
ee89eb2 to
e90359a
Compare
|
Looks like we can't just remove the I'll investigate and see if we can just polyfill the schedule module itself in that test. |
|
Ah - we need to support importing this module even in a node environment, that's what the test is for after all. Glad that test is still there. |
|
Whatever I do to solve this problem with supporting the node environment, it brings up the question of where this scheduler is intended to work. - we need to confirm whether we will make this |
|
ReactDOM: size: 🔺+0.2%, gzip: 🔺+0.1% Details of bundled changes.Comparing: e7bd3d5...4785e74 react-dom
react-art
react-scheduler
Generated by 🚫 dangerJS |
|
Hmm the bundle size went up more than I expected |
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.
Other than some code size nits, looks good to go!
Property names are harder to minify; I don't think our build script mangles them. So we should minimize the number of locations where we access properties by assigning them to variables.
For example, instead of:
if (obj.longPropertyName !== null) {
doSomething(obj.longPropertyName);
}Do this instead:
const l = obj.longPropertyName;
if (l !== null) {
doSomething(l);
}Could you also consider shorter names for the callback config properties?
| */ | ||
| if (callbackConfig.nextCallbackConfig !== null) { | ||
| // we have a nextCallbackConfig | ||
| const nextCallbackConfig = callbackConfig.nextCallbackConfig; |
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.
Code size nits incoming:
Lift this line above the condition so you only have to read callbackConfig.nextCallbackConfig once.
|
|
||
| if (callbackConfig.previousCallbackConfig !== null) { | ||
| // we have a previousCallbackConfig | ||
| const previousCallbackConfig = callbackConfig.previousCallbackConfig; |
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.
Same here. Lift this above the conditional.
|
|
||
| if (callbackConfig.previousCallbackConfig !== null) { | ||
| // we have a previousCallbackConfig | ||
| const previousCallbackConfig = callbackConfig.previousCallbackConfig; |
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.
And here.
In fact, since we always end up checking these values, we can move the variables to the top of the function.
|
Sweet! Will take your recommendations about how to slim down this module. |
NOTE: This PR depends on facebook#12880 and facebook#12884 Please review those first, and after they land Flarnie will rebase on top of them. --- **what is the change?:** See title **why make this change?:** This seems to make the code simpler, and potentially saves space of having an array and object around holding references to the callbacks. **test plan:** Run existing tests
**what is the change?:** - Removed conditional which fell back to 'setTimeout' when the environment doesn't have DOM. This appears to be an old polyfill used for test environments and we don't use it any more. - Fixed type definitions around the callbackID to be more accurate in the scheduler itself, and more loose in the React code. **why make this change?:** To get Flow passing, simplify the scheduler code, make things accurate. **test plan:** Run tests and flow.
**what is the change?:** Adding verification that 'previousCallbackConfig' and 'nextCallbackConfig' are not null before accessing properties on them. Slightly concerned because this implementation relies on these properties being untouched and correct on the config which is passed to 'cancelScheduledWork' but I guess we already rely heavily on that for this whole approach. :\ **why make this change?:** To get Flow passing. Not sure why it passed earlier and in CI, but now it's not. **test plan:** `yarn flow dom` and other flow tests, lint, tests, etc.
**what is the change?:** We had tried removing the fallback implementation of `scheduler` but tests reminded us that this is important for supporting isomorphic uses of React. Long term we will move this out of the `schedule` module but for now let's keep things simple. **why make this change?:** Keep things working! **test plan:** Ran tests and flow
**what is the change?:** `previousScheduledCallback` -> `prev` `nextScheduledCallback` -> `next` **why make this change?:** We want this package to be smaller, and less letters means less code means smaller! **test plan:** ran existing tests
75377a9 to
e123aec
Compare
…ck storage (#12893) * [schedule] Use linked list instead of queue and map for storing cbs NOTE: This PR depends on facebook/react#12880 and facebook/react#12884 Please review those first, and after they land Flarnie will rebase on top of them. --- **what is the change?:** See title **why make this change?:** This seems to make the code simpler, and potentially saves space of having an array and object around holding references to the callbacks. **test plan:** Run existing tests * minor style improvements * refactor conditionals in cancelScheduledWork for increased clarity * Remove 'canUseDOM' condition and fix some flow issues w/callbackID type **what is the change?:** - Removed conditional which fell back to 'setTimeout' when the environment doesn't have DOM. This appears to be an old polyfill used for test environments and we don't use it any more. - Fixed type definitions around the callbackID to be more accurate in the scheduler itself, and more loose in the React code. **why make this change?:** To get Flow passing, simplify the scheduler code, make things accurate. **test plan:** Run tests and flow. * Rewrite 'cancelScheduledWork' so that Flow accepts it **what is the change?:** Adding verification that 'previousCallbackConfig' and 'nextCallbackConfig' are not null before accessing properties on them. Slightly concerned because this implementation relies on these properties being untouched and correct on the config which is passed to 'cancelScheduledWork' but I guess we already rely heavily on that for this whole approach. :\ **why make this change?:** To get Flow passing. Not sure why it passed earlier and in CI, but now it's not. **test plan:** `yarn flow dom` and other flow tests, lint, tests, etc. * ran prettier * Put back the fallback implementation of scheduler for node environment **what is the change?:** We had tried removing the fallback implementation of `scheduler` but tests reminded us that this is important for supporting isomorphic uses of React. Long term we will move this out of the `schedule` module but for now let's keep things simple. **why make this change?:** Keep things working! **test plan:** Ran tests and flow * Shorten properties stored in objects by sheduler **what is the change?:** `previousScheduledCallback` -> `prev` `nextScheduledCallback` -> `next` **why make this change?:** We want this package to be smaller, and less letters means less code means smaller! **test plan:** ran existing tests * further remove extra lines in scheduler
Edit: Rebased and now there is no cruft on this PR. :)
what is the change?:
See title
why make this change?:
This seems to make the code simpler, and potentially saves space of
having an array and object around holding references to the callbacks.
test plan:
Run existing the new and improved tests, from the previous PR.