Search code examples
javascriptdownloadblobencodeuricomponentcreateobjecturl

Creating and downloading text file from string in JavaScript: Blob/createObjectURL vs. encodeURIComponent


As I've been looking for a way to create and download a text file from a website with JavaScript, I've found a bunch of solutions but generally using either Blob/createObjectURL or otherwise encodeURIComponent, with the former being more popular from what I've seen. Below I show two examples: note that only one-two lines in the beginning are different in the two functions (which I noted in comments).

Blob/createObjectURL:

function dl_as_file_Blob(filename_to_dl, data_to_dl) {
    let blobx = new Blob([data_to_dl], { type: 'text/plain' }); // ! Blob
    let elemx = window.document.createElement('a');
    elemx.href = window.URL.createObjectURL(blobx); // ! createObjectURL
    elemx.download = filename_to_dl;
    elemx.style.display = 'none';
    document.body.appendChild(elemx);
    elemx.click();
    document.body.removeChild(elemx);
}

encodeURIComponent:

function dl_as_file_URI(filename_to_dl, data_to_dl) {
    let elemx = document.createElement('a');
    elemx.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(data_to_dl); // ! encodeURIComponent
    elemx.download = filename_to_dl;
    elemx.style.display = 'none';
    document.body.appendChild(elemx);
    elemx.click();
    document.body.removeChild(elemx);
}

What I'd like to know is whether there is any reason to prefer one over the other. So far I could find two small differences. First, encodeURIComponent is more widely supported by browsers than createObjectURL. Second, Blob seems not to support encoding. Based on this, I'd choose the encodeURIComponent solution, but I wonder if there is a reason for why I see the Blob/createObjectURL solution more often.

EDIT: The question above is quite general, so let me narrow down a bit for my specific use case: I want to allow users to download a simple (utf-8), relatively small (max 100-200 kB) text (the results of a completed self-assessment test). There is no really sensitive data involved, and the file is only needed for this purpose alone, on the client-side. Nonetheless, I also welcome more general answers, since I'm curious about the differences.


Solution

  • I wonder if there is a reason for why I see the Blob/createObjectURL solution more often.

    IMHO there are a few possible reasons:

    TL;DR

    1. Performance

    2. Security

    3. API access

    4. It is an object

    5. It looks cooler


    1. Performance

    • You have full control of the content.

    • You can store and access very large amount of data: very fast (async, worker threads) to/from the Web, the local filesystem, local databases, and also other windows and workers.

    • You can store Objects in a performant way.

    • Content can be accessed as text, as typed arrays, or as URLs.

    • You can splitt stored data: for better performance results (gains are like static lenght arrays vs dynamic ones).

    • Blobs you can store in memory or on disks.

    • Blobs can be read from and written to/from the Web, the local.

    • Garbage collection.

    Most importantly, client-side JavaScript File object is a subtype of Blob, a File is just a Blob of data: with a name and a modification date. You can obtain File objects from <input type="file"> elements and from the drag-and-drop API.

    2. Security

    • You have full control of the content. (at least for now)

    • CORS: Blob is same origin, while data: has to be specified in the cors rules, btw data: can be used to be/do evil things.

    • You can do even much more evil things with data:, but this should not be posted/discussed here.

    3. API access

    Once you have a Blob, there are various things you can do with it, many of them symmetrical to the items above:

    • You can send a Blob to another window or worker thread with postMessage().

    • You can store a Blob in a client-side database.

    • You can upload a Blob to a server by passing it to the send() method of an XMLHttpRequest object. (remember, a File object is just a specialized kind of Blob).

    • You can use the createObjectURL() function to obtain a special blob:// URL that refers to the content of a `Blob, and then use this URL with the DOM or with CSS.

    • You can use a FileReader object to asynchronously (or synchronously, in a worker thread) extract the content of a Blob into a string or ArrayBuffer.

    • You can use the Filesystem API and the FileWriter object to write a Blob into a local file.

    4. It is an object

    • I think, i don't need to enter this discussion :D

    5. It looks cooler

    • A short Blob URL looks much better than for example a 4096 kB string.

    • You can do much more cool stuff with Blob.

    sources: