Skip to content
This repository has been archived by the owner on Dec 31, 2020. It is now read-only.

Use Finalization registry to dispose reactions of uncommitted components #332

Merged
merged 12 commits into from
Nov 6, 2020

Conversation

Bnaya
Copy link
Member

@Bnaya Bnaya commented Oct 30, 2020

background: mobxjs/mobx#2562

On this PR we introduce additional mechanism to dispose reactions from uncommitted components

The new mechanism will kick-in when platforms supports finalization registry

High-level changes:
reactionCleanupTracking now expose slightly different api that is covering both mechanisms,
so useObserver is agnostic to the actual impl

Test changes:
The tests now must run using node 14 + --expose-gc
We test both impls with single jest run

Code change checklist

  • Added/updated unit tests
  • Updated README if applicable

@changeset-bot
Copy link

changeset-bot bot commented Oct 30, 2020

🦋 Changeset detected

Latest commit: 7c7a58b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
mobx-react-lite Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@benjamingr
Copy link
Member

@littledan - I don't know if this is interesting to you but I remember talking about use cases and behaviours for FinalizationRegistry some time ago (in the Node collab summit). This is a pretty solid one where React no longer guarantees it will call cleanup functions, MobX needs to run cleanup sometime in the future after the state/object is no longer retained and MobX will use a FinalizationRegistry to accomplish this.

I would be curious about whether or not you think this is a good idea (it's not like we have a choice anyway 😅 🤷‍♂️ )

@Bnaya
Copy link
Member Author

Bnaya commented Oct 30, 2020

@littledan - I don't know if this is interesting to you but I remember talking about use cases and behaviours for FinalizationRegistry some time ago (in the Node collab summit). This is a pretty solid one where React no longer guarantees it will call cleanup functions, MobX needs to run cleanup sometime in the future after the state/object is no longer retained and MobX will use a FinalizationRegistry to accomplish this.

I would be curious about whether or not you think this is a good idea (it's not like we have a choice anyway 😅 🤷‍♂️ )

Worth nothing that, this comes to replace heuristic, setTimeout based user-land garbage collector.
If the component wasn't committed after XXX time, we will dispose the reaction.

@Bnaya Bnaya force-pushed the finalizationregistry-based-dispose branch from 0fdc5c4 to 44a41ef Compare November 1, 2020 12:48
@coveralls
Copy link

coveralls commented Nov 1, 2020

Coverage Status

Coverage increased (+1.08%) to 94.828% when pulling ea86716 on finalizationregistry-based-dispose into 365c3e3 on master.

@Bnaya Bnaya force-pushed the finalizationregistry-based-dispose branch from c63c079 to cf1ff3b Compare November 1, 2020 13:27
@Bnaya Bnaya changed the title finalization registry based dispose poc Use Finalization registry to dispose reactions of uncommitted components Nov 1, 2020
.circleci/config.yml Outdated Show resolved Hide resolved
test/utils.ts Outdated Show resolved Hide resolved
jest.config.js Outdated Show resolved Hide resolved
package.json Outdated
@@ -23,8 +23,9 @@
"prettier": "prettier --write \"./{src,test}/*.{js,ts,tsx}\"",
"lint": "eslint . --ext .js,.ts,.tsx",
"validate": "tsc --noEmit",
"test": "jest --watch",
"test:ci": "jest -i --coverage",
"jest": "node --expose-gc $(yarn bin jest)",
Copy link
Member Author

Choose a reason for hiding this comment

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

This will not work on windows machines.
Any idea what we can do there?

Copy link
Collaborator

Choose a reason for hiding this comment

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

And why do we need it exactly?

Copy link
Member Author

@Bnaya Bnaya Nov 1, 2020

Choose a reason for hiding this comment

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

On the Finalization registry test we use that to force GC so the cleanup will run.
I'v tried other ways without much success.
I can give it another try

Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

It doesn't work on windows because of the bash not because of --expose-gc (that works on windows).

$(yarn bin jest) expands to the jest location. I think since the path is already supposed to be set I would use NODE_FLAGS with cross-env (to set them up in Windows).

Alternatively, I think it's fine not to run this test on Windows.

Copy link
Member Author

Choose a reason for hiding this comment

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

NODE_FLAGS dose not work with expose gc unfortunately,
Using that package seems working, i will push it soon

@Bnaya Bnaya marked this pull request as ready for review November 1, 2020 13:43
throw new Error("This test must run with node >= 14 and --expose-gc flag")
}

const store = mobx.observable({ count1: 0, count2: 0 })
Copy link
Member Author

Choose a reason for hiding this comment

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

We may explicitly share this code part with the test with timers

.circleci/config.yml Show resolved Hide resolved
src/useObserver.ts Outdated Show resolved Hide resolved
src/useObserver.ts Outdated Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
src/utils/reactionCleanupTracking.ts Outdated Show resolved Hide resolved
src/utils/reactionCleanupTracking.ts Outdated Show resolved Hide resolved
resetCleanupScheduleForTests,
forceCleanupTimerToRunNowForTests
} = FinalizationRegistryMaybeUndefined
? createReactionCleanupTrackingUsingFinalizationRegister(FinalizationRegistryMaybeUndefined)
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be nice to separate each of these methods into a separate file. For easier maintenance in case, we want to drop timers eventually.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@Bnaya After splitting this I think we merge :)

@mweststrate
Copy link
Member

Didn't review the tests, but the logic itself looks solid to me! Awesome approach :)

@@ -10,3 +10,9 @@ export function enableDevEnvironment() {
process.env.NODE_ENV === "production"
}
}

export function sleep(time: number) {
Copy link
Member

Choose a reason for hiding this comment

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

This can be promise/timers or util.promisify(setTimeout) :]

Copy link
Member

@benjamingr benjamingr left a comment

Choose a reason for hiding this comment

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

Echoing @mweststrate 's suggestion that this is useful for more than MobX react and should probably be published as a separate package as well as a generic "useCleanup" hook as well probably?

@Bnaya
Copy link
Member Author

Bnaya commented Nov 4, 2020

I will address the comments & do more browsers testing tomorrow,
Hopefully also merge it

@danielkcz danielkcz merged commit fafb136 into master Nov 6, 2020
@danielkcz danielkcz deleted the finalizationregistry-based-dispose branch November 6, 2020 16:04
@github-actions github-actions bot mentioned this pull request Nov 6, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants