Skip to content

Use CPP Base64 Encoder for better performance (>10x) #4884

Closed

Description

@krystofwoldrich

Description

Hermes offers builtin btoa, using it or vendoring react-native-quick-base64, will bring 10x+ improvement in the event processing time.

Things to consider

Activity

  1. Nodonisko commented on Jun 4, 2025

    @Nodonisko

    There is also function utf8ToBytes that is very slow. This function could possibly use native TextEncoder which should speed it up significantly. Here is implementation I used (10x - 15x faster than JS implementation):

    /**
     * Converts a UTF-8 string to an array of bytes using native TextEncoder.
     * This function is intended as a more performant alternative to the
     * utf8ToBytes function found in some Buffer polyfills.
     *
     * @param {string} string The string to convert.
     * @param {number} [unitsInput] Optional. Similar to the 'units' in the polyfill's
     * utf8ToBytes, this aims to limit the number of bytes.
     * If 0, undefined, null, or NaN, it's treated as Infinity
     * (no limit), mimicking the polyfill's `|| Infinity` behavior.
     * Otherwise, the output byte array will be truncated to this length.
     * @returns {number[]} An array of numbers, where each number represents a byte.
     */
    export function utf8ToBytes(string, unitsInput) {
      let units;
    
      // Mimic the polyfill's `units = units || Infinity` behavior for common falsy values
      // that would lead to `Infinity` in the original.
      if (unitsInput === undefined ||
          unitsInput === null ||
          unitsInput === 0 || // Original `|| Infinity` makes 0 effectively Infinity
          (typeof unitsInput === 'number' && Number.isNaN(unitsInput))) {
        units = Infinity;
      } else {
        units = Number(unitsInput); // Coerce to number (e.g., if it was a string "10")
        if (Number.isNaN(units)) {  // If coercion results in NaN (e.g., from "abc")
          units = Infinity;
        }
      }
    
      const encoder = new TextEncoder(); // UTF-8 by default
      const uint8Array = encoder.encode(string);
    
      let finalUint8Array;
    
      if (units < 0) {
        // If units was specified as a negative number not caught by the Infinity conditions.
        // The polyfill would also likely break immediately or produce no bytes.
        finalUint8Array = new Uint8Array(0);
      } else if (units !== Infinity && uint8Array.length > units) {
        // Truncate if the encoded length is greater than the specified units.
        // Ensure units is not negative for slice, though above logic should handle most.
        finalUint8Array = uint8Array.slice(0, Math.max(0, units));
      } else {
        // No truncation needed or units is Infinity
        finalUint8Array = uint8Array;
      }
    
      return finalUint8Array;
    }
  2. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Jun 4, 2025
  3. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Jun 6, 2025
  4. huuphat1908 commented on Oct 7, 2025

    @huuphat1908

    Totally agree. utf8ToBytes is too slow

  5. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Oct 7, 2025
  6. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Oct 7, 2025
  7. added 3 commits that reference this issue on Jun 18, 2026
    2ddb7d2
    ff9001b
    2bea191
  8. added a commit that references this issue on Jun 25, 2026
    ab203f9
  9. github-actions commented on Jul 2, 2026

    @github-actions
    Contributor

    A PR closing this issue has just been released 🚀

    This issue was referenced by PR #6351, which was included in the 8.17.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions