Text parsing · · updated
Base64 encoding vs binary Blobs: memory pitfalls of data URIs
Base64 turns 3 bytes into 4 ASCII characters. JavaScript strings store those characters as UTF-16, so memory can be several times the original Blob. Data URLs prepend a header and keep the whole file in the DOM or CSS. For files, keep a Blob and createObjectURL. For JWT segments and small secrets, Base64url is appropriate. Use the Base64 encoder for text and image to Base64 only when a field demands a data URL.
The 4/3 expansion and UTF-16
1 MB binary → ~1.33 MB Base64 characters → ~2.66 MB as a JS string. Plus the original Blob if you still hold it. That is why FileReader.readAsDataURL on a 40 MB video is a bad idea. File to Base64 should warn on large files. Hashing those files belongs in chunked checksums, not in a string.
btoa versus readAsDataURL versus createObjectURL
btoa is small strings. readAsDataURL is convenience and memory. createObjectURL is a short blob: URL that streams from the Blob. Prefer the last for previews and downloads. Image to Base64 exists for rich-text fields that only accept data URLs; canvas compression should emit a Blob download by default.
String.fromCharCode spread stack overflows
btoa(String.fromCharCode(...uint8)) blows the stack on large arrays. Chunk the conversion. Or skip Base64 and keep the Blob. JWT segments are small enough that this does not matter; see decode JWTs locally.
CSP and data: scripts
data: text/javascript is an XSS gift. SRI does not apply the way you want. Do not generate executable data URLs in a helper. If you must embed an image, data:image/png;base64,... is a document size problem, not a script problem.
When Base64 is the right tool
JWT, basic auth, small JSON fields, email MIME. Files, PDFs, and photos should stay Blobs until a format demands ASCII. Base64 to file and Base64 to image reverse the mistake of a pasted data URL.
Tools
Base64 encoder / decoder, file to Base64, image to Base64, JWT inspector.
Worked example: preview an image without a data URL
User drops a 12 MB PNG. The wrong path is FileReader.readAsDataURL, assign to img.src, then canvas-compress. You now hold the Blob, a 16 MB string, and a decoded bitmap. The right path: URL.createObjectURL(file) for preview, createImageBitmap for encode, revoke the URL in finally. Download the result as a Blob. Never stringify the file.
If a CMS field only accepts a data URL, compress first with the image compressor, then image to Base64 on the small output. That is the only honest use of Base64 for photos. JWT and tiny JSON fields are the other honest use — JWT inspector is Base64url on purpose.
Measure: performance.memory or just watch the task manager. A hung tab after “convert to Base64” is the 4/3 × UTF-16 tax. File to Base64 should refuse or chunk. Hashing should never Base64 first; slice and digest the binary.
Object URL leaks show up as memory that never drops after many previews. Revoke. If you must persist a preview across routes, keep the File in state, not a URL string in localStorage (localStorage cannot hold Blobs anyway, and stuffing Base64 there is how you freeze a phone).
Frequently asked questions
Why does btoa throw on Unicode?
btoa expects bytes as a binary string. Encode UTF-8 first (TextEncoder) then btoa, or use the Base64 encoder.
Is a data URL the same as Base64?
A data URL is a scheme plus optional media type plus often Base64. CSP may block data: scripts. Do not generate executable data URLs.
When should I revoke object URLs?
After the download or img is done. Leaking URLs pins Blobs. See Blob slicing.