Skip to content

Slow module initialization time on low-end devices #4463

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

Closed
gaearon opened this issue Jun 17, 2024 · 11 comments
Closed

Slow module initialization time on low-end devices #4463

gaearon opened this issue Jun 17, 2024 · 11 comments

Comments

@gaearon
Copy link
Contributor

gaearon commented Jun 17, 2024

Which package?

@formatjs/intl-pluralrules/polyfill

Describe the bug

While not a bug per se, merely importing @formatjs/intl-pluralrules/polyfill causes a one second stall on a low-end Android device in a React Native project. For context, this is ~1s out of ~3.5s of our startup time, i.e. this polyfill is almost a third of the entire app's initialization time (which uses many other libraries including RN core itself).

I'm not sure what's special about this polyfill in particular. Maybe it's hitting some bad case. From inspecting the code, one thing that jumps out to me is that it pulls in the entirety of @formatjs/ecma402-abstract because it targets CJS, so a bunch of code gets initialized just to get invariant, FormatNumericToString, and ToNumber. Maybe publishing an ESM version would avoid that.

To Reproduce

This is reproducible with the Bluesky app (fully open source) on Samsung Galaxy A12. If there is interest, I can give more detailed instructions, but it's essentially about installing it, running yarn, then yarn android to run it on an Android simulator (assuming you have one set up).

@gaearon
Copy link
Contributor Author

gaearon commented Jun 18, 2024

It seems like the issue is that the best fit matcher is very inefficient. You can see this by running the polyfill code unconditionally in Chrome with 6x CPU throttling.

Screenshot 2024-06-18 at 15 59 40

@longlho
Copy link
Member

longlho commented Jun 18, 2024

yeah best fit matching is non-trivial. The algorithm is in LDML here. At a high level it has to calculate the distance between the requested locale and the dataset, taken into account some special regional grouping & preference like Latin America, then take the shortest one. We've already put in some shortcuts wrt local distance calculation, but overall it's quite heavy. Getting this to match icu4j is pretty tricky. I can take another look, but no promises.

@gaearon
Copy link
Contributor Author

gaearon commented Jun 18, 2024

Cool, thanks. Would it be possible to offer a version of the polyfill that does 'lookup' instead?

Also, in general, something feels pathological about, say, passing en and then spending so much initialization time doing something. Zooming out of the specific CPU work being done here — is there any way something could be precomputed here? How do I explain it to myself why this CPU work needs to happen during initialization? Or maybe, could any of this work be shifted towards when it's absolutely necessary?

@longlho
Copy link
Member

longlho commented Jun 18, 2024

yeah because the 1st thing it tries to do is detect whether this platform needs polyfilling, which checks for a specific Chrome bug. If you're running on a platform that you know definitely needs polyfilling, you can import /polyfill-force instead.

The lookup locale algorithm is pretty bad, as it basically just removes 1 subtag at a time when trying to match, which would yield false negative for things like traditional Chinese.

@gaearon
Copy link
Contributor Author

gaearon commented Jun 18, 2024

If you're running on a platform that you know definitely needs polyfilling, you can import /polyfill-force instead.

Fantastic, this hasn't even occurred to me but it's exactly what I needed.

@gaearon
Copy link
Contributor Author

gaearon commented Jun 18, 2024

It would be still be great to somehow get this fixed upstream because I bet it's affecting a lot of RN apps that use @formatjs transitively. Most developers aren't aware how to debug init time issues so it probably translates to second stalls across a lot of apps.

@gaearon
Copy link
Contributor Author

gaearon commented Jun 18, 2024

Actually nvm, I guess developers do include the polyfill itself manually so this was probably our mistake. Would be good to call it out in docs maybe.

@gaearon
Copy link
Contributor Author

gaearon commented Jun 18, 2024

Thanks a lot for holding my hand through this, the last insight let me cut off a few hundred more ms.

Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@github-actions github-actions bot added the Stale label Jul 19, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 26, 2024
@sregg
Copy link

sregg commented Aug 2, 2024

We improved our app start time by 3x by just replacing all polyfill imports with their -force versions.
That's 2s instead of 7s on my Pixel 6 Pro.
Thanks @gaearon for the hint 🙏

@gaearon
Copy link
Contributor Author

gaearon commented Aug 3, 2024

Might be dicey but seems like a good moment to kick off a discussion on how to avoid this slowing down more apps. It sucks that many apps will add this polyfill without testing perf and the users will be stuck with bad startup perf as a result.

#4485

longlho pushed a commit that referenced this issue Aug 30, 2024
compojoom added a commit to safe-global/safe-wallet-monorepo that referenced this issue Mar 17, 2025
compojoom added a commit to safe-global/safe-wallet-monorepo that referenced this issue Mar 17, 2025
compojoom added a commit to safe-global/safe-wallet-monorepo that referenced this issue Mar 17, 2025
We rely on `notation: „compact“`, but it is not available in Hermes yet. We can use some polyfills from formatjs to do the trick for us.

fix(mobile): use the -force polyfill

formatjs/formatjs#4463 (comment)
compojoom added a commit to safe-global/safe-wallet-monorepo that referenced this issue Mar 17, 2025
We rely on `notation: „compact“`, but it is not available in Hermes yet. We can use some polyfills from formatjs to do the trick for us.

fix(mobile): use the -force polyfill

formatjs/formatjs#4463 (comment)
compojoom added a commit to safe-global/safe-wallet-monorepo that referenced this issue Mar 17, 2025
* fix(mobile): use polyfills for Intl.formatNumber (#5362)

We rely on `notation: „compact“`, but it is not available in Hermes yet. We can use some polyfills from formatjs to do the trick for us.

formatjs/formatjs#4463 (comment)

---------

Co-authored-by: Daniel Dimitrov <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants