ArrayBuffer and views are a part of ECMA standard, a part of JavaScript.
In the browser, there are additional higher-level objects, described in File API, in particular Blob.
Blob consists of an optional string type (a MIME-type usually), plus blobParts – a sequence of other Blob objects, strings and BufferSource.
The constructor syntax is:
new Blob(blobParts, options);
blobPartsis an array ofBlob/BufferSource/Stringvalues.optionsoptional object:type–Blobtype, usually MIME-type, e.g.image/png,endings– whether to transform end-of-line to make theBlobcorrespond to current OS newlines (\r\nor\n). By default"transparent"(do nothing), but also can be"native"(transform).
For example:
// create Blob from a string
let blob = new Blob(["<html>…</html>"], {type: 'text/html'});
// please note: the first argument must be an array [...]
// create Blob from a typed array and strings
let hello = new Uint8Array([72, 101, 108, 108, 111]); // "Hello" in binary form
let blob = new Blob([hello, ' ', 'world'], {type: 'text/plain'});
We can extract Blob slices with:
blob.slice([byteStart], [byteEnd], [contentType]);
byteStart– the starting byte, by default 0.byteEnd– the last byte (exclusive, by default till the end).contentType– thetypeof the new blob, by default the same as the source.
The arguments are similar to array.slice, negative numbers are allowed too.
Blob objects are immutableWe can’t change data directly in a Blob, but we can slice parts of a Blob, create new Blob objects from them, mix them into a new Blob and so on.
This behavior is similar to JavaScript strings: we can’t change a character in a string, but we can make a new corrected string.
Blob as URL
A Blob can be easily used as a URL for <a>, <img> or other tags, to show its contents.
Thanks to type, we can also download/upload Blob objects, and the type naturally becomes Content-Type in network requests.
Let’s start with a simple example. By clicking on a link you download a dynamically-generated Blob with hello world contents as a file:
<!-- download attribute forces the browser to download instead of navigating -->
<a download="hello.txt" href='#' id="link">Download</a>
<script>
let blob = new Blob(["Hello, world!"], {type: 'text/plain'});
link.href = URL.createObjectURL(blob);
</script>
We can also create a link dynamically in JavaScript and simulate a click by link.click(), then download starts automatically.
Here’s the similar code that causes user to download the dynamically created Blob, without any HTML:
let link = document.createElement('a');
link.download = 'hello.txt';
let blob = new Blob(['Hello, world!'], {type: 'text/plain'});
link.href = URL.createObjectURL(blob);
link.click();
URL.revokeObjectURL(link.href);
URL.createObjectURL takes a Blob and creates a unique URL for it, in the form blob:<origin>/<uuid>.
That’s what the value of link.href looks like:
blob:https://javascript.info/1e67e00e-860d-40a5-89ae-6ab0cbee6273
For each URL generated by URL.createObjectURL the browser stores a URL → Blob mapping internally. So such URLs are short, but allow to access the Blob.
A generated URL (and hence the link with it) is only valid within the current document, while it’s open. And it allows to reference the Blob in <img>, <a>, basically any other object that expects a URL.
There’s a side effect though. While there’s a mapping for a Blob, the Blob itself resides in the memory. The browser can’t free it.
The mapping is automatically cleared on document unload, so Blob objects are freed then. But if an app is long-living, then that doesn’t happen soon.
So if we create a URL, that Blob will hang in memory, even if not needed any more.
URL.revokeObjectURL(url) removes the reference from the internal mapping, thus allowing the Blob to be deleted (if there are no other references), and the memory to be freed.
In the last example, we intend the Blob to be used only once, for instant downloading, so we call URL.revokeObjectURL(link.href) immediately.
In the previous example with the clickable HTML-link, we don’t call URL.revokeObjectURL(link.href), because that would make the Blob url invalid. After the revocation, as the mapping is removed, the URL doesn’t work any more.
Blob to base64
An alternative to URL.createObjectURL is to convert a Blob into a base64-encoded string.
That encoding represents binary data as a string of ultra-safe “readable” characters with ASCII-codes from 0 to 64. And what’s more important – we can use this encoding in “data-urls”.
A data url has the form data:[<mediatype>][;base64],<data>. We can use such urls everywhere, on par with “regular” urls.
For instance, here’s a smiley:
<img src="data:image/png;base64,R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMlWLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mAbiwWtuf0uxFAgA7">