What you Don’t know:

WeakMap you don’t know

What is a Blob

Binary Large Object (Blob) indicates a Large Object of Binary type. In a database management system, binary data is stored as a collection of single individuals. A Blob is usually a video, sound, or multimedia file. In JavaScript, objects of type Blob represent immutable raw data similar to file objects. To get an intuitive feel for Blob objects, let’s first create a myBlob object using the Blob constructor, as shown in the figure below:

As you can see, the myBlob object has two properties: size and Type. The size attribute is used to indicate the size of the data in bytes, and type is a string of MIME types. A Blob does not necessarily represent data in a JavaScript native format. The File interface, for example, is based on the Blob, inheriting the functionality of the Blob and extending it to support files on the user’s system.

Introduction to Blob API

A Blob consists of an optional string type (usually MIME type) and blobParts:

Multipurpose Internet Mail Extensions (MIME) Enables a file with a certain extension to be opened by an application. When the file is accessed, the browser automatically opens the file using the specified application. Used to specify some custom client file names, and some media file opening methods.

HTML text/ HTML, PNG image. PNG image/ PNG, and TXT text/plain are common MIME types.

2.1 Constructors

The syntax for the Blob constructor is:

var aBlob = new Blob(blobParts, options);
Copy the code

The related parameters are described as follows:

  • BlobParts: This is an array of objects consisting of ArrayBuffer, ArrayBufferView, Blob, DOMString, etc. DOMStrings will be encoded as UTF-8.
  • Options: An optional object containing the following two properties:
    • Type — The default is""Which represents the MIME type of the array contents to be put into the BLOB.
    • The default is “endings”"transparent", which specifies to include a line terminator\nHow the string is written to. It is one of two values:"native", which means the line terminator will be changed to a newline suitable for the host operating system file system, or"transparent", which means that the ending character saved in the BLOB is kept unchanged.

Example 1: Creating bloBs from strings

let myBlobParts = ['<html><h2>Hello Semlinker</h2></html>']; // an array consisting of a single DOMString
let myBlob = new Blob(myBlobParts, {type : 'text/html'.endings: "transparent"}); // the blob

console.log(myBlob.size + " bytes size");
// Output: 37 bytes size
console.log(myBlob.type + " is the type");
// Output: text/html is the type
Copy the code

Example 2: Creating bloBs from typed arrays and strings

let hello = new Uint8Array([72.101.108.108.111]); // Binary format "hello"
let blob = new Blob([hello, ' '.'semlinker'] and {type: 'text/plain'});
Copy the code

After introducing the Blob constructor, let’s look at the properties and methods of the Blob class:

2.2 attributes

We already know that a Blob object contains two properties:

  • Size (read-only) : indicatesBlobThe size, in bytes, of the data contained in the object.
  • Type (read-only) : a string indicating theBlobThe MIME type of the data contained in the object. If the type is unknown, the value is an empty string.

2.3 methods

  • Slice ([start[, end[, contentType]]]) : Returns a new Blob object containing the specified range of data from the source Blob object.
  • Stream () : Returns a ReadableStream that reads the contents of the BLOB.
  • Text () : Returns a Promise object containing all of the blob’s contents in UTF-8 format USVString.
  • ArrayBuffer () : arrayBuffer that returns a Promise object and contains all of the bloB’s contents in binary format.

The important thing to note here is that Blob objects are immutable. We can’t change data directly in a Blob, but we can split a Blob, create new Blob objects from it, and mix them into a new Blob. This behavior is similar to JavaScript strings: we cannot change the characters in the string, but we can create new, corrected strings.

Iii. Blob Usage Scenarios

3.1 Uploading fragments

The File object is a special type of Blob and can be used in any Blob type context. Therefore, in the case of large file transfer, we can use the slice method to cut large files and then upload them into fragments. The specific example is as follows:

const file = new File(["a".repeat(1000000)]."test.txt");

const chunkSize = 40000;
const url = "https://httpbin.org/post";

async function chunkedUpload() {
  for (let start = 0; start < file.size; start += chunkSize) {
      const chunk = file.slice(start, start + chunkSize + 1);
      const fd = new FormData();
      fd.append("data", chunk);

      await fetch(url, { method: "post".body: fd }).then((res) = >res.text() ); }}Copy the code

3.2 Downloading Data from the Internet

We can download data from the Internet and store it in a Blob object using the following methods, such as:

const downloadBlob = (url, callback) = > {
	const xhr = new XMLHttpRequest()
	xhr.open('GET', url)
	xhr.responseType = 'blob'
	xhr.onload = (a)= > {
    callback(xhr.response)
	}
	xhr.send(null)}Copy the code

Of course, in addition to using the XMLHttpRequest API, we can also use the FETCH API to stream binary data. Here we look at how to use the FETCH API to fetch images and display them locally. The implementation is as follows:

const myImage = document.querySelector('img');
const myRequest = new Request('flowers.jpg');

fetch(myRequest)
  .then(function(response) {
    return response.blob();
  })
 .then(function(myBlob) {
   let objectURL = URL.createObjectURL(myBlob);
   myImage.src = objectURL;
});
Copy the code

When the fetch request succeeds, we call the blob() method of the response object, read a BLOb object from the response object, and then create an objectURL using createObjectURL(). It is then assigned to the SRC attribute of the img element to display the image.

3.3 Blob Used as URL

Blobs can easily be used as urls for , , or other tags. Thanks to the type attribute, we can also upload/download Blob objects. Here’s an example of a Blob file download, but before we get to that we need to briefly introduce Blob urls.

1.Blob URL/Object URL

Blob URL/Object URL is a pseudo-protocol that allows Blob and File objects to be used as URL sources for images, download binary data links, and so on. In the browser, we use the url.createObjecturl method to create the Blob URL. This method takes a Blob object and creates a unique URL for it in the form of Blob :

/

.

blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f641
Copy the code

The browser internally stores a URL → Blob mapping for each URL generated through url.createObjECturl. As a result, such urls are shorter, but can access bloBs. The generated URL is valid only as long as the current document is open. It allows references to blobs in , , but if you access a Blob URL that no longer exists, you will receive a 404 error from the browser.

The Blob URL above looks good, but it actually has a side effect. Although the URL → Blob mapping is stored, the Blob itself still resides in memory and the browser cannot free it. The mapping is automatically cleared when the document is uninstalled, so the Blob object is subsequently released. However, if the application has a long life, that won’t happen anytime soon. So, if we create a Blob URL, even if the Blob is no longer needed, it will still be in memory.

To address this, we can call the url.revokeobjecturl (URL) method to remove the reference from the internal map, allowing the Blob to be removed (if there are no other references) and freeing up memory. Next, let’s look at a concrete example of a Blob file download.

2. Example of downloading Blob files

index.html


      
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Sample Blob file download</title>
  </head>

  <body>
    <button id="downloadBtn">File download</button>
    <script src="index.js"></script>
  </body>
</html>
Copy the code

index.js

const download = (fileName, blob) = > {
  const link = document.createElement("a");
  link.href = URL.createObjectURL(blob);
  link.download = fileName;
  link.click();
  link.remove();
  URL.revokeObjectURL(link.href);
};

const downloadBtn = document.querySelector("#downloadBtn");
downloadBtn.addEventListener("click", (event) => {
  const fileName = "blob.txt";
  const myBlob = new Blob(["A thorough understanding of the Blob Web API"] and {type: "text/plain" });
  download(fileName, myBlob);
});
Copy the code

In our example, we create a Blob object of type “text/plain” by calling the Blob constructor, and then download the file by dynamically creating a tag.

3.4 Converting Blob to Base64

An alternative to URl.createObjECturl is to convert the Blob to a Base64-encoded string. Base64 is a representation of binary data based on 64 printable characters. It is used to represent, transmit, and store some binary data, including MIME E-mail and some complex data in XML, when processing text data.

In MIME E-mail, Base64 can be used to encode binary byte sequence data into text composed of a sequence of ASCII characters. When used, base64 is specified in the transport encoding. The characters used include 26 upper and lower Latin letters, 10 digits, plus sign (+), and slash (/), a total of 64 characters, and the equal sign (=) is used as a suffix.

Let’s show you how to embed A Base64-encoded image in HTML. When writing HTML pages, for some simple images, it is usually chosen to embed the image content directly in the page, so as to reduce unnecessary network requests, but the image data is binary data, how to embed? Most modern browsers support a feature called Data URLs, which allows you to use Base64 to encode binary Data from an image or other file and embed it as a text string inside a Web page.

Data URLs consist of four parts: a prefix (Data:), a MIME type indicating the Data type, optional Base64 markup if it’s not text, and the Data itself:

data:[<mediatype>][;base64],<data>
Copy the code

Mediatype is a string of MIME type, such as “image/jpeg” for a JPEG image file. If omitted, the default value is text/plain; Charset = US – ASCII. If the data is of text type, you can embed the text directly (using the appropriate entity or escape characters, depending on the document type). For binary data, you can base64 encode the data and then embed it. Like embedding an image:

<img alt="logo" src="data:image/png; base64,iVBORw0KGgoAAAANSUhEUg...">
Copy the code

Note, however, that if the image is large and has a rich color hierarchy, it is not appropriate to use this method, because the large base64-encoded string of the image will significantly increase the size of the HTML page, which will affect the loading speed. In addition, using FileReader API, we can also facilitate the realization of local image preview function, the specific code is as follows:

<input type="file" accept="image/*" onchange="loadFile(event)">
<img id="output"/>

<script>
  const loadFile = function(event) {
    const reader = new FileReader();
    reader.onload = function(){
      const output = document.querySelector('output');
      output.src = reader.result;
    };
    reader.readAsDataURL(event.target.files[0]);
  };
</script>
Copy the code

In the example above, we bind the onChange event handler loadFile to the file type input box. Within this function, we create a FileReader object and bind the object to the onLoad event handler. The FileReader object’s readAsDataURL() method is then called to convert the File object corresponding to the local image into a DataURL.

After previewing the image locally, we can submit the Data to the Data URLs of the image directly to the server. In this case, the server needs to do some related processing to save the uploaded pictures normally. Here take Express as an example, and the specific processing code is as follows:

const app = require('express') (); app.post('/upload'.function(req, res){
    let imgData = req.body.imgData; // Get the base64 image data in the POST request
    let base64Data = imgData.replace(/^data:image\/\w+; base64,/."");
    let dataBuffer = Buffer.from(base64Data, 'base64');
    fs.writeFile("image.png", dataBuffer, function(err) {
        if(err){
          res.send(err);
        }else{
          res.send("Picture uploaded successfully!"); }}); });Copy the code

For FileReader objects, in addition to supporting converting Blob/File objects to Data urls, it also provides readAsArrayBuffer() and readAsText() methods, Use to convert Blob/File objects to other data formats. Here’s an example of readAsArrayBuffer() :

// Get arrayBuffer from bloB
let fileReader = new FileReader();

fileReader.onload = function(event) {
  let arrayBuffer = fileReader.result;
};
fileReader.readAsArrayBuffer(blob);
Copy the code

3.5 Image Compression

In some cases, you might want to reduce the amount of data transferred when uploading a local image by compressing it before submitting it to the server. To compress images on the front end, we can use the Canvas object’s toDataURL() method, which takes two optional parameters, Type and encoderOptions.

Type indicates the image format, which is image/ PNG by default. EncoderOptions is used to indicate the image quality, which can be selected from 0 to 1 if the image format is specified as Image/JPEG or Image /webp. If the value is out of range, the default value of 0.92 will be used and other parameters will be ignored.

Let’s take a look at how to achieve specific image compression:

// compress.js
const MAX_WIDTH = 800; // The maximum width of the image

function compress(base64, quality, mimeType) {
  let canvas = document.createElement("canvas");
  let img = document.createElement("img");
  img.crossOrigin = "anonymous";
  return new Promise((resolve, reject) = > {
    img.src = base64;
    img.onload = (a)= > {
      let targetWidth, targetHeight;
      if (img.width > MAX_WIDTH) {
        targetWidth = MAX_WIDTH;
        targetHeight = (img.height * MAX_WIDTH) / img.width;
      } else {
        targetWidth = img.width;
        targetHeight = img.height;
      }
      canvas.width = targetWidth;
      canvas.height = targetHeight;
      let ctx = canvas.getContext("2d");
      ctx.clearRect(0.0, targetWidth, targetHeight); // Clear the canvas
      ctx.drawImage(img, 0.0, canvas.width, canvas.height);
      let imageData = canvas.toDataURL(mimeType, quality / 100);
      resolve(imageData);
    };
  });
}
Copy the code

For the image Data returned in the Data URL format, to further reduce the amount of Data transferred, we can convert it to a Blob object:

function dataUrlToBlob(base64, mimeType) {
  let bytes = window.atob(base64.split(",") [1]);
  let ab = new ArrayBuffer(bytes.length);
  let ia = new Uint8Array(ab);
  for (let i = 0; i < bytes.length; i++) {
    ia[i] = bytes.charCodeAt(i);
  }
  return new Blob([ab], { type: mimeType });
}
Copy the code

After the transformation is complete, we can wrap the Blob object of the compressed image in the FormData object and submit it to the server via AJAX:

function uploadFile(url, blob) {
  let formData = new FormData();
  let request = new XMLHttpRequest();
  formData.append("image", blob);
  request.open("POST", url, true);
  request.send(formData);
}
Copy the code

In addition to the toDataURL() method, the Canvas object also provides a toBlob() method, which has the following syntax:

canvas.toBlob(callback, mimeType, qualityArgument)
Copy the code

The toBlob() method is asynchronous compared to the toDataURL() method, so it has an additional callback parameter. The first parameter of this callback method is the converted blob file information by default.

With that said, let’s look at a complete example of local image compression:


      
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Local image compression</title>
  </head>
  <body>
    <input type="file" accept="image/*" onchange="loadFile(event)" />
    <script src="./compress.js"></script>
    <script>
      const loadFile = function (event) {
        const reader = new FileReader();
        reader.onload = async function () {
          let compressedDataURL = await compress(
            reader.result,
            90."image/jpeg"
          );
          let compressedImageBlob = dataUrlToBlob(compressedDataURL);
          uploadFile("https://httpbin.org/post", compressedImageBlob);
        };
        reader.readAsDataURL(event.target.files[0]);
      };
    </script>
  </body>
</html>
Copy the code

3.6 Generating a PDF Document

PDF (Portable Document Format) is a Document Format developed by Adobe Systems in 1993 for use in the Document clearing house. On the browser side, it is also easy to generate PDF documents using some available open source libraries, such as jsPDF.


      
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>The client generates the PDF sample</title>
  </head>
  <body>
    <h3>The client generates the PDF sample</h3>
    <script src="https://unpkg.com/jspdf@latest/dist/jspdf.min.js"></script>
    <script>
      (function generatePdf() {
        const doc = new jsPDF();
        doc.text("Hello semlinker!".66.88);
        const blob = new Blob([doc.output()], { type: "application/pdf" });
        blob.text().then((blobAsText) = > {
          console.log(blobAsText); }); }) ();</script>
  </body>
</html>
Copy the code

In the above example, we first create a PDF document object and then call the text() method on that object to add Hello Semlinker! At the specified coordinate point. Then we use the generated PDF content to create the corresponding Blob object, it is important to note that we set the Blob type to Application/PDF, and finally we convert the content saved in the Blob object into text and output to the console. Because of the amount of content, we only list a few output results here:

%PDF - 1.3
%DHS to decide such a
3 0 obj
<</Type /Page
/Parent 1 0 R
/Resources 2 0 R
/MediaBox [0 0 595.28 841.89]
/Contents 4 0 R
>>
endobj
....
Copy the code

In addition to supporting plain text, jsPDF can also generate PDF documents with images, such as:

let imgData = 'data:image/jpeg; base64,/9j/4AAQSkZJRgABAQEASABIAAD/... '
let doc = new jsPDF();

doc.setFontSize(40)
doc.text(35.25.'Paranyan loves jsPDF')
doc.addImage(imgData, 'JPEG'.15.40.180.160)
Copy the code

There are many application scenarios of Blob, but we will not list them here. Interested partners can consult relevant information by themselves.

The difference between Blob and ArrayBuffer

An ArrayBuffer object is used to represent a generic, fixed-length buffer of raw binary data. You can’t directly manipulate the contents of an ArrayBuffer. Instead, you need to create a typed array object or DataView object that represents the buffer in a specific format and uses that object to read and write the contents of the buffer.

Objects of type Blob represent immutable raw data similar to file objects. A Blob does not necessarily represent data in a JavaScript native format. The File interface is based on Blob, inheriting the FUNCTIONALITY of Blob and extending it to support files on the user’s system.

4.1 the Blob vs ArrayBuffer

  • Unless you need to use the write/edit capabilities provided by ArrayBuffer, the Blob format is probably best.
  • Blob objects are immutable, whereas arrayBuffers can be manipulated with TypedArrays or DataViews.
  • Arraybuffers are stored in memory and can be manipulated directly. Blobs, on the other hand, can reside on disk, cache memory, and other unavailable locations.
  • Although blobs can be passed directly as arguments to other functions, such aswindow.URL.createObjectURL(). However, you may still need a File API such as FileReader to work with bloBs.
  • Blob and ArrayBuffer objects can be converted to each other:
    • The use of FileReaderreadAsArrayBuffer()Method to convert a Blob object to an ArrayBuffer object
    • Use the Blob constructor, such asnew Blob([new Uint8Array(data]);To convert an ArrayBuffer object to a Blob object.

For HTTP scenarios, such as AJAX scenarios, Blob and ArrayBuffer can be used in the following ways:

function GET(url, callback) {
  let xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'arraybuffer'; // or xhr.responseType = "blob";
  xhr.send();

  xhr.onload = function(e) {
    if(xhr.status ! =200) {
      alert("Unexpected status code " + xhr.status + " for " + url);
      return false;
    }
    callback(new Uint8Array(xhr.response)); // or new Blob([xhr.response]);
  };
}
Copy the code

After understanding the above content, I believe some readers may feel more than enough. So, what’s more to learn about the Blob? My next plan is based on Deno source code, to gradually analyze the concrete implementation of DenoBlob. The implementation of the url.createObjecturl () method and the revokeObjectURL() method will also be analyzed in passing.

5. Reference Resources

  • MDN – Blob
  • MDN – Data URLs
  • javascript.info – blob
  • flaviocopes – blob
  • arraybuffer-vs-blob
  • javascript-interview-question-what-is-a-blob