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

[schedule 1/n] Support cancelling scheduled callback with an id #12743

Closed

Conversation

flarnie
Copy link
Contributor

@flarnie flarnie commented May 4, 2018

what is the change?:
-> Stores an id for each callback, removes it after callback is cancelled or called.
-> We don't use 'Map' because this library is intended for use outside of React, don't want to add dependency on a polyfill if we can avoid it.
-> We may eventually just use a linked list, but I still like the simplicity of being able to cancel the callback in O(1) time using some kind of key/value storage with the id.
-> Since we have a callback, timeout, and id which are always used together, makes sense to store them in an object. Also once we store multiple callbacks will need to create objects to store these pieces of data for each. If we really want to avoid creating objects, could use arrays with data for a given callback at the same index, or we could use object pooling. Would explore that in a later PR, seems like a premature optimization though.

why make this change?:
Once we support multiple callbacks you will need to use the id to
specify which callback you mean.

Also storing the callback data in an object sets us up nicely for storing an array of pending callback configs.

test plan:
Added a new test for cIC and ran all tests.

**what is the change?:**
see title

**why make this change?:**
Once we support multiple callbacks you will need to use the id to
specify which callback you mean.

**test plan:**
Added a test, ran all tests, lint, etc.
@flarnie flarnie requested a review from acdlite May 4, 2018 17:44
// Avoid using 'catch' to keep errors easy to debug
} finally {
// always clean up the callbackId, even if the callback throws
delete registeredCallbackIds[callbackId];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will later refactor this for error handling, but for now this works.

@pull-bot
Copy link

pull-bot commented May 4, 2018

ReactDOM: size: 🔺+0.2%, gzip: 🔺+0.3%

Details of bundled changes.

Comparing: 25dda90...be7254b

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.development.js +0.2% +0.3% 611.89 KB 613.27 KB 141.4 KB 141.78 KB UMD_DEV
react-dom.production.min.js 🔺+0.2% 🔺+0.3% 100.07 KB 100.28 KB 31.84 KB 31.95 KB UMD_PROD
react-dom.development.js +0.2% +0.3% 596.26 KB 597.64 KB 137.23 KB 137.62 KB NODE_DEV
react-dom.production.min.js 🔺+0.2% 🔺+0.3% 98.51 KB 98.72 KB 31.07 KB 31.17 KB NODE_PROD
ReactDOM-dev.js +0.2% +0.3% 620.7 KB 622.08 KB 140 KB 140.39 KB FB_WWW_DEV
ReactDOM-prod.js 🔺+0.2% 🔺+0.3% 284.23 KB 284.92 KB 51.94 KB 52.12 KB FB_WWW_PROD

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-art.development.js +0.3% +0.4% 414.79 KB 416.2 KB 90.31 KB 90.72 KB UMD_DEV
react-art.production.min.js 🔺+0.2% 🔺+0.5% 90.39 KB 90.61 KB 27.49 KB 27.63 KB UMD_PROD
react-art.development.js +0.4% +0.6% 340.63 KB 342.04 KB 71.63 KB 72.04 KB NODE_DEV
react-art.production.min.js 🔺+0.4% 🔺+0.6% 54.92 KB 55.13 KB 16.78 KB 16.88 KB NODE_PROD
ReactART-dev.js +0.4% +0.6% 348.89 KB 350.3 KB 71.22 KB 71.62 KB FB_WWW_DEV
ReactART-prod.js 🔺+0.4% 🔺+0.6% 166.97 KB 167.68 KB 27.44 KB 27.61 KB FB_WWW_PROD

react-scheduler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-scheduler.development.js +13.5% +11.8% 10.2 KB 11.58 KB 3.6 KB 4.02 KB UMD_DEV
react-scheduler.production.min.js 🔺+12.9% 🔺+13.4% 1.58 KB 1.79 KB 860 B 975 B UMD_PROD
react-scheduler.development.js +13.8% +12.0% 10.01 KB 11.39 KB 3.55 KB 3.97 KB NODE_DEV
react-scheduler.production.min.js 🔺+12.3% 🔺+14.4% 1.66 KB 1.86 KB 871 B 996 B NODE_PROD

Generated by 🚫 dangerJS

@flarnie flarnie changed the title Support cancelling scheduled callback with an id [schedule 1/n] Support cancelling scheduled callback with an id May 4, 2018
@flarnie
Copy link
Contributor Author

flarnie commented May 8, 2018

waiting_puppies_ping

Copy link
Contributor

@bvaughn bvaughn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change looks okay, but I'm not very familiar with this module yet, so someone else should probably also review it. I'm also a little confused by one of the comments.

let timeoutTime = -1;
// Number.MAX_SAFE_INTEGER is not supported in IE
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
let callbackIdCounter = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Why not init to 0? 😄

if (options != null && typeof options.timeout === 'number') {
timeoutTime = now() + options.timeout;
}
// This assumes that we only schedule one callback at a time because that's
// how Fiber uses it.
const latestCallbackId = getCallbackId();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Why "latest"? Isn't it actually a "new" id?

callback(frameDeadlineObject);
}
scheduledCallbackConfig = null;
safelyCallScheduledCallback(callback, callbackId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be a separate function call? I guess it could get inlined anyway so it probably doesn't matter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does eventually get called in multiple places, and will be more complex once we implement error handling.

if (options != null && typeof options.timeout === 'number') {
timeoutTime = now() + options.timeout;
}
// This assumes that we only schedule one callback at a time because that's
// how Fiber uses it.
Copy link
Contributor

@bvaughn bvaughn May 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment should be above scheduledCallbackConfig = {...} rather than the call to getCallbackId.

But also, the comment confuses me a little. A lot of this module seems written to support multiple, concurrent callbacks (like the fact that rIC returns an id and adds to a registeredCallbackIds map).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is laying the groundwork for support to multiple callbacks, yes. I have a follow-up PR that implements that support, just breaking things into multiple steps.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the comment - it's outdated, will remove either in this PR or the next.

let isIdleScheduled = false;
let timeoutTime = -1;
// Number.MAX_SAFE_INTEGER is not supported in IE
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

screen shot 2018-05-09 at 1 05 32 pm

I don't think we need to account for the counter exceeding the maximum integer :D

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never close tabs, man.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will remove, thanks!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s a century in JavaScript Library Years.

@flarnie
Copy link
Contributor Author

flarnie commented May 9, 2018

Will fix the commented items in the follow-up PR, and since this is a subset of that PR closing this one in favor of fixing and merging #12746

@flarnie flarnie closed this May 9, 2018
flarnie added a commit to flarnie/react that referenced this pull request May 9, 2018
flarnie added a commit that referenced this pull request May 9, 2018
* Support using id to cancel scheduled callback

**what is the change?:**
see title

**why make this change?:**
Once we support multiple callbacks you will need to use the id to
specify which callback you mean.

**test plan:**
Added a test, ran all tests, lint, etc.

* ran prettier

* fix lint

* Use object for storing callback info in scheduler

* Wrap initial test in a describe block

* Support multiple callbacks in `ReactScheduler`

**what is the change?:**
We keep a queue of callbacks instead of just one at a time, and call
them in order first by their timeoutTime and then by the order which
they were scheduled in.

**why make this change?:**
We plan on using this module to coordinate JS outside of React, so we
will need to schedule more than one callback at a time.

**test plan:**
Added a boatload of shiny new tests. :)

Plus ran all the old ones.

NOTE: The tests do not yet cover the vital logic of callbacks timing
out, and later commits will add the missing test coverage.

* Heuristic to avoid looking for timed out callbacks when none timed out

**what is the change?:**
Tracks the current soonest timeOut time for all scheduled callbacks.

**why make this change?:**
We were checking every scheduled callback to see if it timed out on
every tick. It's more efficient to skip that O(n) check if we know that
none have timed out.

**test plan:**
Ran existing tests.

Will write new tests to cover timeout behavior in more detail soon.

* Put multiple callback support under a disabled feature flag

**what is the change?:**
See title

**why make this change?:**
We don't have error handling in place yet, so should maintain the old
behavior until that is in place.

But want to get this far to continue making incremental changes.

**test plan:**
Updated and ran tests.

* Hide support for multiple callbacks under a feature flag

**what is the change?:**
see title

**why make this change?:**
We haven't added error handling yet, so should not expose this feature.

**test plan:**
Ran all tests, temporarily split out the tests for multiple callbacks
into separate file. Will recombine once we remove the flag.

* Fix nits from code review

See comments on #12743

* update checklist in comments

* Remove nested loop which calls additional timed out callbacks

**what is the change?:**
We used to re-run any callbacks which time out whilst other callbacks
are running, but now we will only check once for timed out callbacks
then then run them.

**why make this change?:**
To simplify the code and the behavior of this module.

**test plan:**
Ran all existing tests.

* Remove feature flag

**what is the change?:**
see title

**why make this change?:**
Because only React is using this, and it sounds like async. rendering
won't hit any different behavior due to these changes.

**test plan:**
Existing tests pass, and this allowed us to recombine all tests to run
in both 'test' and 'test-build' modes.

* remove outdated file

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

Successfully merging this pull request may close these issues.

6 participants