Thanks to visit codestin.com
Credit goes to github.com

Skip to content

new DurationFormat is very slow on React Native / Hermes #4936

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

Open
cambecc opened this issue Mar 28, 2025 · 5 comments
Open

new DurationFormat is very slow on React Native / Hermes #4936

cambecc opened this issue Mar 28, 2025 · 5 comments
Labels

Comments

@cambecc
Copy link

cambecc commented Mar 28, 2025

Which package?

"@formatjs/intl-durationformat": "0.7.4"

Describe the bug

Instantiating instances of DurationFormat is very slow on React Native / Hermes:

const start = Date.now();
new Intl.DurationFormat("en");
console.log(`took ${Date.now() - start} ms`);

Output:

took 610 ms

I believe #4522 is likely the same issue.

Screenshots

This flamegraph is a little rough but demonstrates where the cost is going:

Image

Smartphone:

  • Device: iOS Simulator
  • OS: iOS 18.1
  • React Native: 0.76.6

Investigation

Locale matching is known to be particularly slow on React Native / Hermes (#4276). Because of this, caching of Intl objects is recommended.
Unfortunately, the instantiation of even one instance of DurationFormat heavily impacts performance, taking about 600 ms on my machine.

The reason appears to be due to DurationFormat passing 700+ locales as the availableLocales argument to ResolveLocale. Other Intl objects like NumberFormat or ListFormat do not have this problem because the set of available locales is opt-in via imports of locale-data. DurationFormat appears to be unique in that all locale data is automatically made available (probably in time-separators.generated.ts)?

@cambecc cambecc added the bug label Mar 28, 2025
@cambecc
Copy link
Author

cambecc commented Mar 28, 2025

Looking into this a bit more, during a single instantiation of DurationFormat, isMatched gets invoked a little over 1 million times.

Some quick optimizations, like memoizing languageMatchInfoLocale.split('-') and manually flattening expandedMatchedRegions instead of using map/reduce, cut the execution time by 30%. More simple tweaks like this can be done, but I expect the real benefit would be finding a cheaper way to implement locale matching.

@longlho
Copy link
Member

longlho commented Mar 28, 2025

Thanks for reporting. I'll take a look. Polyfills have traditionally been more locale-data-bound than CPU bound, so for polyfills where the dataset is small we ship them w/ everything.

@jessbennett
Copy link

I’ve seen this issue in older Mono repos.
Clear the cache and re-test localization files using react testing library. This should boost performance.

Copy link

github-actions bot commented May 3, 2025

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 May 3, 2025
@cambecc
Copy link
Author

cambecc commented May 3, 2025

I use this abomination (once, as early as possible) to remove all the locales I don't need:

void function fixDurationFormatPerf() {
    const localesToKeep = new Set<string>(["en", "ja", "fr"]);
    const availableLocales: Set<string> = (Intl.DurationFormat as any).availableLocales ?? new Set();

    for (const locale of availableLocales) {
        if (!localesToKeep.has(locale)) {
            availableLocales.delete(locale);
        }
    }
}();

This function directly mutates the availableLocales internal set, reducing it from ~700 entries to just a handful. Doesn't change the O(n^2) complexity of ResolveLocale, but at least makes n small enough to be usable.

@github-actions github-actions bot removed the Stale label May 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants