diff --git a/4-binary/03-blob/article.md b/4-binary/03-blob/article.md index 1fae9f9bc0..207bd72435 100644 --- a/4-binary/03-blob/article.md +++ b/4-binary/03-blob/article.md @@ -1,69 +1,69 @@ # Blob -`ArrayBuffer` and views are a part of ECMA standard, a part of JavaScript. +`ArrayBuffer` 和视图(views)都是 JavaScript 中 ECMA 标准的一部分。 -In the browser, there are additional higher-level objects, described in [File API](https://www.w3.org/TR/FileAPI/), in particular `Blob`. +我们在 [File API](https://www.w3.org/TR/FileAPI/) 一节中描述过,在浏览器中,有其他高阶对象,特别是 `Blob`。 -`Blob` consists of an optional string `type` (a MIME-type usually), plus `blobParts` -- a sequence of other `Blob` objects, strings and `BufferSources`. +`Blob` 由一个可选的字符串 `type` (通常是 MIME 类型) 和 `blobParts` 组成 -- 一串其他 `Blob` 对象、字符串和 `BufferSources`。 ![](blob.svg) -The constructor syntax is: +构造函数的语法为: ```js new Blob(blobParts, options); ``` -- **`blobParts`** is an array of `Blob`/`BufferSource`/`String` values. -- **`options`** optional object: - - **`type`** -- blob type, usually MIME-type, e.g. `image/png`, - - **`endings`** -- whether to transform end-of-line to make the blob correspond to current OS newlines (`\r\n` or `\n`). By default `"transparent"` (do nothing), but also can be `"native"` (transform). +- **`blobParts`** `Blob`/`BufferSource`/`String` 类型值的数组。 +- **`options`** 可选对象: + - **`type`** -- blob 类型,通常是 MIME 类型,如 `image/png`, + - **`endings`** -- 是否转换换行符,使 blob 符合当前操作系统的换行符(`\r\n` 或 `\n`)。默认为 `"transparent"`(啥也不做),不过也可以是 `"native"`(转换)。 -For example: +例如: ```js -// create Blob from a string +// 从字符串创建 blob let blob = new Blob(["…"], {type: 'text/html'}); -// please note: the first argument must be an array [...] +// 请注意:第一个参数值必须是数组 [...] ``` ```js -// create Blob from a typed array and strings -let hello = new Uint8Array([72, 101, 108, 108, 111]); // "hello" in binary form +// 从类型数组(typed array)和字符串创建 blob +let hello = new Uint8Array([72, 101, 108, 108, 111]); // 二进制格式的 "hello" let blob = new Blob([hello, ' ', 'world'], {type: 'text/plain'}); ``` -We can extract blob slices with: +我们可以用 slice 方法来提取 blob 分段: ```js blob.slice([byteStart], [byteEnd], [contentType]); ``` -- **`byteStart`** -- the starting byte, by default 0. -- **`byteEnd`** -- the last byte (exclusive, by default till the end). -- **`contentType`** -- the `type` of the new blob, by default the same as the source. +- **`byteStart`** -- 起始字节,默认为 0。 +- **`byteEnd`** -- 最后一个字节(不包括之,默认为最后)。 +- **`contentType`** -- 新 blob 的 `type`,默认与源 blob 相同。 -The arguments are similar to `array.slice`, negative numbers are allowed too. +参数值与 `array.slice` 相同,也允许负数。 -```smart header="Blobs are immutable" -We can't change data directly in a blob, but we can slice parts of blobs, create new blobs from them, mix them into a new blob and so on. +```smart header="Blob 是不可改变的" +我们不能直接在 blob 中更改数据,但可以切割成多个部分,从每一部分创建新的 blobs,将他们组成新的 blob,以此类推。 -This behavior is similar to JavaScript strings: we can't change a character in a string, but we can make a new corrected string. +这种行为类似于 JavaScript 字符串:我们无法更改字符串中的字符,但可以生成一个新的改动过的字符串。 ``` -## Blob as URL +## Blob 作为 URL -A Blob can be easily used as an URL for ``, `` or other tags, to show its contents. +Blob 可以很容易当做 URL 用于 ``、`` 或其他标记(tags),来显示其内容。 -Thanks to `type`, we can allso download/upload blobs, and it naturally becomes `Content-Type` in network requests. +有了 `type`,我们也可以下载/上传 blobs,很自然的便成了网络请求中的 `Content-Type`。 -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: +让我们来看一个简单的例子。通过\ + 点击一个链接,下载一个动态生成的 blob,文件内容是 `hello world`: ```html run - + Download ``` -We can also create a link dynamically in JavaScript and simulate a click by `link.click()`, then download starts automatically. +我们也可以在 Javascript 中动态创建一个链接,通过 `link.click()` 模拟一个点击(click),然后便自动下载了。 -Here's the similar code that causes user to download the dynamicallly created Blob, without any HTML: +以下是示例代码,用户无需任何 HTML 即可下载动态生成的 Blob: ```js run let link = document.createElement('a'); @@ -90,50 +90,50 @@ link.click(); URL.revokeObjectURL(link.href); ``` -`URL.createObjectURL` takes a blob and creates an unique URL for it, in the form `blob:/`. +`URL.createObjectURL` 接受一个 blob,为其创建一个唯一的 URL,格式是 `blob:/`。 -That's what the value of `link.href` looks like: +`link.href` 的值就像这样: ``` blob:https://javascript.info/1e67e00e-860d-40a5-89ae-6ab0cbee6273 ``` -The browser for each url generated by `URL.createObjectURL` stores an the url -> blob mapping internally. So such urls are short, but allow to access the blob. +浏览器内部为每个通过 `URL.createObjectURL` 生成的 url 存储了一个 url -> blob 映射。因此,这些 url 虽然短小,但可以访问 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 ``, ``, basically any other object that expects an url. +生成的 url(即其链接)只在当前文档打开的状态下才有效。它允许引用 ``、`` 中的 blob,以及基本上任何其他接受 url 的对象。 -There's a side-effect though. While there's an mapping for a blob, the blob itself resides in the memory. The browser can't free it. +不过有个问题是,当 blob 有映射的时候,blob 本身是在内存中的。浏览器无法释放它。 -The mapping is automatically cleared on document unload, so blobs are freed then. But if an app is long-living, then that doesn't happen soon. +在文档退出时,该映射会被自动清除,因此 blob 也相应被释放了。但是如果应用程序长时间工作时,这个释放工作就不会很快发生了。 -**So if we create an URL, that blob will hang in memory, even if not needed any more.** +**因此,如果我们要创建一个 URL,那个 blob 会长留在内存中,即使已不再需要了。** -`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. +`URL.revokeObjectURL(url)` 从内部映射中删除引用,因此允许删除 blob(如果没有其他引用的话),并从内存中释放。 -In the last example, we intend the blob to be used only once, for instant downloading, so we call `URL.revokeObjectURL(link.href)` immediately. +在上一个示例中,为了快速下载,我们想只用一次 blob,因此我们立刻调用 `URL.revokeObjectURL(link.href)`。 -In the previous example though, 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. +而在前一个示例中,利用可以点击的 HTML 链接,我们不调用 `URL.revokeObjectURL(link.href)`,因为那样会使 blob url 无效。在撤销后,由于映射被删除了,因此 url 也不再有效了。 -## Blob to base64 +## Blob 转换为 base64 -An alternative to `URL.createObjectURL` is to convert a blob into a base64-encoded string. +`URL.createObjectURL` 的一个可替代方法是,将 blob 转换为 base64-编码 的字符串。 -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". +这种编码是将二进制数据表示为一个由 0 到 64 的 ASCII 码字符组成的字符串,非常安全且“可读“。而且更重要的是 -- 我们可以在数据 url 中使用此编码。 -A [data url](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) has the form `data:[][;base64],`. We can use such urls everywhere, on par with "regular" urls. +[数据 url(data url)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) 的格式是 `data:[][;base64],`。我们可以在其他地方使用这种 url,如同使用 "普通" urls 一样。 -For instance, here's a smiley: +例如,这是一个笑容符: ```html ``` -The browser will decode the string and show the image: +浏览器将字符串解码,显示图像: -To transform a blob into base64, we'll use the built-in `FileReader` object. It can read data from Blobs in multiple formats. In the [next chapter](info:file) we'll cover it more in-depth. +我们用自带的 `FileReader` 对象将 blob 转换为 base64。它可以从 Blobs 读取为多种格式的数据。在[下一章](info:file) 我们会做深入讲解。 -Here's the demo of downloading a blob, now via base-64: +以下是下载 blob 的示例代码,这次是通过 base-64 来实现: ```js run let link = document.createElement('a'); @@ -143,7 +143,7 @@ let blob = new Blob(['Hello, world!'], {type: 'text/plain'}); *!* let reader = new FileReader(); -reader.readAsDataURL(blob); // converts the blob to base64 and calls onload +reader.readAsDataURL(blob); // 将 blob 转换为 base64 并调用 onload 方法 */!* reader.onload = function() { @@ -152,70 +152,70 @@ reader.onload = function() { }; ``` -Both ways of making an URL of a blob are usable. But usually `URL.createObjectURL(blob)` is simpler and faster. +这两种从 blob 创建 URL 的方法都可以用。但通常 `URL.createObjectURL(blob)` 更简单快捷一些。 -```compare title-plus="URL.createObjectURL(blob)" title-minus="Blob to data url" -+ We need to revoke them if care about memory. -+ Direct access to blob, no "encoding/decoding" -- No need to revoke anything. -- Performance and memory losses on big blobs for encoding. +```compare title-plus="URL.createObjectURL(blob)" title-minus="Blob 转换为 数据 url" ++ 如介意内存,我们需要撤销他们 ++ 直接访问 blob,无需”编码/解码“ +- 无需撤销任何操作。 +- 大的 blob 编码时,性能和内存会有损耗。 ``` -## Image to blob +## Image 转换为 blob -We can create a blob of an image, an image part, or even make a page screenshot. That's handy to upload it somewhere. +我们可以从图像(image)、图像的一部分或甚至一个页面截图来创建 blob。这样便方便上传到其他地方。 -Image operations are done via `` element: +Image 操作是通过 `` 元素来实现: -1. Draw an image (or its part) on canvas using [canvas.drawImage](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage). -2. Call canvas method [.toBlob(callback, format, quality)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob) that creates a blob and runs `callback` with it when done. +1. 用 [canvas.drawImage](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage)在画布上画一个图像(或其中的一部分)。 +2. 调用 canvas 方法 [.toBlob(callback, format, quality)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob),创建一个 blob,并在创建后运行 `callback`。 -In the example below, an image is just copied, but we could cut from it, or transform it on canvas prior to making a blob: +在上例中,图像只是被复制(copy)了,不过我们可以在创建 blob 之前,在画布上进行剪裁(cut),或转换(transform): ```js run -// take any image +// 获取任何图像 let img = document.querySelector('img'); -// make of the same size +// 生成同尺寸的 let canvas = document.createElement('canvas'); canvas.width = img.clientWidth; canvas.height = img.clientHeight; let context = canvas.getContext('2d'); -// copy image to it (this method allows to cut image) +// 复制图像(此方法允许剪裁图像) context.drawImage(img, 0, 0); -// we can context.rotate(), and do many other things on canvas +// 我们可以在画布上 context.rotate(),以及许多其他操作。 -// toBlob is async opereation, callback is called when done +// toBlob 是异步操作,结束后会调用 callback canvas.toBlob(function(blob) { - // blob ready, download it + // blob 创建完毕后,下载之 let link = document.createElement('a'); link.download = 'example.png'; link.href = URL.createObjectURL(blob); link.click(); - // delete the internal blob reference, to let the browser clear memory from it + // 删除内部 blob 引用,这样浏览器可以从内存中将其删除 URL.revokeObjectURL(link.href); }, 'image/png'); ``` -If we prefer `async/await` instead of callbacks: +如果我们想用 `async/await` 取代 callbacks: ```js let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png')); ``` -For screenshotting a page, we can use a library such as . What it does is just walks the page and draws it on ``. Then we can get a blob of it the same way as above. +对于页面截屏,我们可以用一个库如 。它做的事情是,在页面上扫一遍,并在 `` 上画下来。然后我们便可以如上述操作一样从中获取 blob。 -## From Blob to ArrayBuffer +## Blob 转换为 ArrayBuffer -The `Blob` constructor allows to create a blob from almost anything, including any `BufferSource`. +`Blob` 构造函数允许从几乎任何对象创建 blob,包括任何 `BufferSource`。 -But if we need to perform low-level processing, we can get the lowest-level `ArrayBuffer` from it using `FileReader`: +但如果我们需要做底层操作的话,我们可以用 `FileReader` 从 blob 中获取最底层的 `ArrayBuffer`: ```js -// get arrayBuffer from blob +// 从 blob 获取 arrayBuffer let fileReader = new FileReader(); *!* @@ -228,15 +228,15 @@ fileReader.onload = function(event) { ``` -## Summary +## 总结 -While `ArrayBuffer`, `Uint8Array` and other `BufferSource` are "binary data", a [Blob](https://www.w3.org/TR/FileAPI/#dfn-Blob) represents "binary data with type". +`ArrayBuffer`、`Uint8Array` 和其他 `BufferSource` 是“二进制数据”,[Blob](https://www.w3.org/TR/FileAPI/#dfn-Blob) 则表示“带类型的二进制数据”。 -That makes Blobs convenient for upload/download operations, that are so common in the browser. +这样可以方便 blob用于在浏览器中非常普遍使用的上传/下载操作。 -Methods that perform web-requests, such as [XMLHttpRequest](info:xmlhttprequest), [fetch](info:fetch-basics) and so on, can work with `Blob` natively, as well as with other binary types. +[XMLHttpRequest](info:xmlhttprequest), [fetch](info:fetch-basics) 等进行网络请求的方法可以自然的使用 `Blob`,如同使用其他二进制类型数据一样。 -We can easily convert betweeen `Blob` and low-level binary data types: +`Blob` 和底层二进制数据类型之间的转换也很容易: -- We can make a Blob from a typed array using `new Blob(...)` constructor. -- We can get back `ArrayBuffer` from a Blob using `FileReader`, and then create a view over it for low-level binary processing. +- 我们可以用 `new Blob(...)` 构造函数从一个类型数组(typed array)创建 blob。 +- 我们可以用 `FileReader` 从 Blob 中取回 `ArrayBuffer`,然后在其上创建一个视图(view),用于底层二进制操作。