Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >谁说前端不需要懂二进制

谁说前端不需要懂二进制

作者头像
山月
发布于 2020-06-18 07:42:01
发布于 2020-06-18 07:42:01
1.2K00
代码可运行
举报
运行总次数:0
代码可运行

作为一名前端,在工作中也会遇到很多有关二进制处理的需求,如 EXCEL 表格的导出,PDF 的生成,多个文件的打包,音频的处理。

从前后端整体上来说前端代表 UI 层,它的外在表现是 human readable 的,而服务端代表数据层,所表现出来的是 machine readable。如果 EXCEL 以及 PDF 的处理交由服务端处理,服务端免不了要做一层格式化的逻辑处理,以便与前端保持一致。一来增加了复杂度,二来容易造成前端与服务器端的数据不一致。此时为了减少复杂度,工作量有可能都尽可能在浏览器端完成。

本篇文章总结了浏览器端的二进制以及有关数据之间的转化,如 ArrayBufferTypedArrayBlobDataURLObjectURLText 之间的互相转换。为了更好的理解与方便以后的查询,特意做了一张图做总结。

二进制相互转换图

二进制相关数据类型

在介绍常见的二进制数据处理之前,先简单介绍下几种二进制相关的数据类型

ArrayBuffer && TypedArray

TypedArray 是 ES6+ 新增的描述二进制数据的类数组数据结构。但它本身不可以被实例化,甚至无法访问,你可以把它理解为 Abstract Class 或者 Interface。而基于 TypedArray,有如下数据类型:

  • Uint8ArrayUintUnsigned Int 代表数组的每一项是无符号整型8 代表数据的每一项占 8 个比特位,即一个字节
  • Int8Array
  • Uint16Array
  • Int16Array
  • ...

通过 Uint8Array,即可知道 Uint16ArrayInt8Array 所代表的意义。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const array = new Int32Array([1, 2, 3])

// .length 代表数组的大小
// 3
array.length

// .btyeLength 代表数据所占字节大小
// 12
array.byteLength

ArrayBuffer 代表二进制数据结构,「并且只读」,需要转化为 TypedArray 进行写操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const array = new Int16Array([1, 2, 3])

// TypedArray -> ArrayBuffer
array.buffer

// ArrayBuffer -> TypedArray
new Int16Array(array.buffer)

// buffer.length 代表数据所占用字节大小
array.buffer.length === array.byteLength

连接多个 TypedArray

TypedArray 没有像数组那样的 Array.prototype.concat 方法用来连接多个 TypedArray。不过它提供了 TypedArray.prototype.set 可以用来间接连接字符串

❝可以参考 MDN 文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/set ❞

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 在位移 offset 位置放置 typedarray
typedarray.set(typedarray, offset)

原理就是先分配一块空间足以容纳需要连接的 TypedArray,然后逐一在对应位置叠加

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function concatenate(constructor, ...arrays) {
  let length = 0;
  for (let arr of arrays) {
    length += arr.length;
  }
  let result = new constructor(length);
  let offset = 0;
  for (let arr of arrays) {
    result.set(arr, offset);
    offset += arr.length;
  }
  return result;
}

concatenate(Uint8Array, new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6]))

同时您还需要对资源的获取有大致的了解,如 XHR,fetch,通过文件上传。

Blob

Blob 是浏览器端的类文件对象。操作 Blob 需要使用数据类型 FileReader

FileReader 有以下方法,可以把 Blob 转化为其它数据

  • FileReader.prototype.readAsArrayBuffer
  • FileReader.prototype.readAsText
  • FileReader.prototype.readAsDataURL
  • FileReader.prototype.readAsBinaryString
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const blob = new Blob('hello'.split(''))

// 表示文件的大小
blob.size

const array = new Uint8Array([128, 128, 128])
const blob2 = new Blob([array])

function readBlob (blob, type) {
  return new Promise(resolve => {
    const reader = new FileReader()
    reader.onload = function (e) {
      resolve(e.target.result)
    }
    reader.readAsArrayBuffer(blob)
  })
}

readBlob(blob, 'DataURL').then(url => console.log(url))

数据输入

数据输入或者叫资源的请求可以分为以下两种途径

  • 通过 url 地址请求网络资源
  • 通过文件上传请求本地资源

fetch

fetch 应该是大家比较熟悉的,但大多使用环境比较单一,一般用来请求 json 数据。其实, 「它也可以设置返回数据格式为 Blob 或者 ArrayBuffer。」

fetch 返回一个包含 Response 对象的 Promise,Response 有以下方法

  • Response.prototype.arrayBuffer
  • Response.prototype.blob
  • Response.prototype.text
  • Response.prototype.json

❝详情可以查看 MDN 文档 https://developer.mozilla.org/en-US/docs/Web/API/Response ❞

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fetch('/api/ping').then(res => {
  // true
  console.log(res instanceof Response)
  // 最常见的使用
  return res.json()

  // 返回 Blob
  // return res.blob()

  // 返回 ArrayBuffer
  // return res.arrayBuffer()
})

另外,万能的 Response API 既可以可以使用 TypedArrayBlobText 作为输入,又可以使用它们作为输出。

「这意味着关于这三种数据类型的转换完全可以通过 Response」

xhr

「xhr 可以设置 responseType 接收合适的数据类型」

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const request = new XMLHttpRequest()
request.responseType = 'arraybuffer'
request.responseType = 'blob'

File

本地文件可以通过 input[type=file] 来上传文件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<input type="file" id="input">

当上传成功后,可以通过 document.getElementById('input').files[0] 获取到上传的文件,即一个 File 对象,它是 Blob 的子类,可以通过 FileReader 或者 Response 获取文件内容。

数据输出

或者叫数据展示或者下载,数据经二进制处理后可以由 url 表示,然后通过 image, video 等元素引用或者直接下载。

Data URL

Data URL 即 Data As URL。所以, 「如果资源过大,地址便会很长。」 使用以下形式表示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
data:[<mediatype>][;base64],<data>

先来一个 hello, world。把以下地址粘入地址栏,会访问到 hello, world

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
data:text/html,<h1>Hello%2C%20World!</h1>
Base64 编码与解码

Base64 使用大小写字母,数字,+ 和 / 64 个字符来编码数据,所以称为 Base64。经编码后,文本体积会变大 1/3

在浏览器中,可以使用 atobbtoa 编码解码数据。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// aGVsbG8=
btoa('hello')

Object URL

可以使用浏览器新的 API URL 对象生成一个地址来表示 Blob 数据。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 粘贴生成的地址,可以访问到 hello, world
// blob:http://host/27254c37-db7a-4f2f-8861-0cf9aec89a64
URL.createObjectURL(new Blob('hello, world'.split('')))

下载

data:application/octet-stream;base64,5bGx5pyI

资源的下载可以利用 FileSaver[1] 。

这里也简单写一个函数,用来下载一个链接

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function download (url, name) {
  const a = document.createElement('a')
  a.download = name
  a.rel = 'noopener'
  a.href = url
  // 触发模拟点击
  a.dispatchEvent(new MouseEvent('click'))
  // 或者 a.click(
}

二进制数据转换

二进制数据转换

以上是二进制数据间的转换图,有一些转换可以直接通过 API,有些则需要代码,以下贴几种常见转换的代码

String to TypedArray

根据上图,由字符串到 TypedArray 的转换,可以通过 「String -> Blob -> ArrayBuffer -> TypedArray」 的途径。

关于代码中的函数 readBlob 可以回翻环节 数据类型 - Blob[2]

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const name = '山月'
const blob = new Blob(name.split(''))

readBlob(blob, 'ArrayBuffer').then(buffer => new Uint8Array(buffer))

也可以通过 Response API 直接转换 「String -> ArrayBuffer -> TypedArray」

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const name = '山月'

new Response(name).arrayBuffer(buffer => new Uint8Array(buffer))

这上边两种方法都是直接通过 API 来转化,如果你更像了解如何手动转换一个字符串和二进制的 TypedArray

String to TypedArray 2

使用 enodeURIComponent 把字符串转化为 utf8,再进行构造 TypedArray。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function stringToTypedArray(s) {
  const str = encodeURIComponent(s)
  const binstr = str.replace(/%([0-9A-F]{2})/g, (_, p1) => {
    return String.fromCharCode('0x' + p1)
  })
  return new Uint8Array(binstr.split('').map(x => x.charCodeAt(0)))
}

实践

1. 如何上传本地图片并在网页上展示

由以上整理的转换图得出途径

本地上传图片 -> Blob -> Object URL

2. 如何拼接两个音频文件

由以上整理的转换图得出途径

fetch请求音频资源 -> ArrayBuffer -> TypedArray -> 拼接成一个 TypedArray -> ArrayBuffer -> Blob -> Object URL

3. 如何把 json 数据转化为 demo.json 并下载文件

json 视为字符串,由以上整理的转换图得出途径

Text -> DataURL

除了使用 DataURL,还可以转化为 Object URL 进行下载。关于下载的函数 download,可以参考以上环节 数据输出-下载[3]

Text -> Blob -> Object URL

可以把以下代码直接粘贴到控制台下载文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const json = {
  a: 3,
  b: 4,
  c: 5
}
const str = JSON.stringify(json, null, 2)

// 方案一:Text -> DataURL
const dataUrl = `data:,${str}`
download(dataUrl, 'demo.json')

// 方案二:Text -> Blob -> ObjectURL
const url = URL.createObjectURL(new Blob(str.split('')))
download(url, 'demo1.json')
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈成长之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Protocol Buffers 在前端项目中的使用
公司后端使用的是go语言,想尝试用pb和前端进行交互,于是便有了这一次尝试,共计花了一星期时间,网上能查到的文档几乎都看了一遍,但大多都是教在node环境下如何使用,普通的js环境下很多讲述的并不清楚,于是把自己的采坑之路总结一下,希望能让给大家提供一些参考。
吴裕超
2018/08/01
6.9K0
Protocol Buffers 在前端项目中的使用
前端二进制文件处理
上一篇文章从 W3C 草案的角度入手过了一遍 File API 的几个方法,这一篇尝试梳理一下二进制数据相关的一些方法,有 Blob、ArrayBuffer、Uint8Array、BufferSource 等。
上山打老虎了
2022/06/15
1.7K0
前端二进制文件处理
JS中的二进制数据处理
  在现有的计算机中,二进制常常以字节数组的形式存在于程序当中。例如在C#里面,就用byte[],标准C里面没有byte类型,但可以通过typedef把byte定义为unsigned char的别名,效果是一样的。JS设计之初似乎就没想过要处理二进制,对于字节的概念可以说是非常非常的模糊。如果要表达字节数组,那么似乎只能用一个普通数组来表示。
有赞coder
2021/05/13
3.9K0
JS中的二进制数据处理
前端下载二进制流文件
平时在前端下载文件有两种方式,一种是后台提供一个 URL,然后用 window.open(URL) 下载,另一种就是后台直接返回文件的二进制内容,然后前端转化一下再下载。
谭光志
2020/09/28
3.3K0
ArrayBuffer
ArrayBuffer对象、TypedArray视图和DataView视图是 JavaScript 操作二进制数据的一个接口。这些对象早就存在,属于独立的规格(2011 年 2 月发布),ES6 将它们纳入了 ECMAScript 规格,并且增加了新的方法。它们都是以数组的语法处理二进制数据,所以统称为二进制数组。 这个接口的原始设计目的,与 WebGL 项目有关。所谓 WebGL,就是指浏览器与显卡之间的通信接口,为了满足 JavaScript 与显卡之间大量的、实时的数据交换,它们之间的数据通信必须是二进制的,而不能是传统的文本格式。文本格式传递一个 32 位整数,两端的 JavaScript 脚本与显卡都要进行格式转化,将非常耗时。这时要是存在一种机制,可以像 C 语言那样,直接操作字节,将 4 个字节的 32 位整数,以二进制形式原封不动地送入显卡,脚本的性能就会大幅提升。
小小杰啊
2022/12/21
2.6K0
从web图片裁剪出发:了解H5中的Blob
刚开始做前端的时候,有个功能卡住我了,就是裁剪并上传头像。当时两个方案摆在我面前,一个是flash,我不会。另一个是通过iframe上传图片,然后再上传坐标由后端裁剪,而我最终的选择是后者。有人会疑惑,为什么不用H5的Canvas和FormData,第一要考虑ie8的兼容性,第二那时候眼界没到,这种新东西光是听听都怕。   后来随着Mobile项目越做越多,类似的功能开发得也越来越多,Canvas+FormData成为了标配方案。但做的多了却一直没有静下心来研究,浏览器怎么使用H5的方式裁剪并把文件发送出去
李海彬
2018/03/27
2.3K0
从web图片裁剪出发:了解H5中的Blob
web 直播流的解析
本文作者:ivweb villainthr Web 进制操作是一个比较底层的话题,因为平常做业务的时候根本用不到太多,或者说,根本用不到。 老铁,没毛病 那什么情况会用到呢? canvas webso
腾讯IVWEB团队
2017/07/14
4.1K2
web 直播流的解析
Blob、File、ArrayBuffer、TypedArray、DataView究竟应该如何应用
Blob、File、ArrayBuffer、TypedArray、DataView、Object URL ..等等 Web 应用中有关于进制的应用你了解多少?
19组清风
2022/05/11
2K0
Blob、File、ArrayBuffer、TypedArray、DataView究竟应该如何应用
Blob、ArrayBuffer、File、FileReader和FormData的区别
Blob、ArrayBuffer、File、FileReader、FormData这些名词总是经常看到,知道一点又好像不知道,像是同一个东西好像又不是,总是模模糊糊,最近终于下决心要弄清楚。
码客说
2019/10/22
5.3K0
JavaScript奇技淫巧:执行“二进制”代码
如果将JavaScript代码转化成能执行的二进制字符串,是不是很有意思呢?起码看起来会很酷,运行效果如下图:
用户8703799
2023/05/09
6540
【前端知乎】443- ArrayBuffer 与 Blob 对象详解
ArrayBuffer 对象是 ES6 才纳入正式 ECMAScript 规范,是 JavaScript 操作二进制数据的一个接口。ArrayBuffer 对象是以数组的语法处理二进制数据,也称二进制数组。
pingan8787
2019/12/24
2K0
【前端知乎】443- ArrayBuffer 与 Blob 对象详解
js操作二进制数据
使用ArrayBuffer对象保存二进制数据,使用TypedArray和DataView 视图来读写数据。
风花一世月
2024/03/19
4790
js操作二进制数据
内功修炼之lodash—— clone&amp;cloneDeep(一定有你遗漏的js基础知识)
本文实现方法都是看效果倒推实现方法,并进行一些拓展和思考,和源码无关。lodash这个库在这里更像一个题库,给我们刷题的
lhyt
2022/09/21
1.6K0
内功修炼之lodash—— clone&amp;cloneDeep(一定有你遗漏的js基础知识)
前端本地文件操作与上传
前端无法像原生APP一样直接操作本地文件,否则的话打开个网页就能把用户电脑上的文件偷光了,所以需要通过用户触发,用户可通过以下三种方式操作触发:
IT派
2018/08/10
1.9K0
前端本地文件操作与上传
聊聊JS的二进制家族:Blob、ArrayBuffer和Buffer
事实上,前端很少涉及对二进制数据的处理,但即便如此,我们偶尔总能在角落里看见它们的身影。
啦啦啦321
2019/12/19
8.8K0
【前端知乎系列】ArrayBuffer 和 Blob 对象
ArrayBuffer 对象与 Blob 对象大家或许不太陌生,常见于文件上传操作处理(如处理图片上传预览等问题)。
pingan8787
2019/12/16
2.3K0
【前端知乎系列】ArrayBuffer 和 Blob 对象
JS中Buffer数据详解
随着WebSocket、WebAudio、Ajax2等广泛应用,前端方面只要是处理大数据或者想提高数据处理性能,那一定是少不了 ArrayBuffer对象
jinghong
2020/05/09
6.9K0
《你不知道的 Blob》番外篇
原文对 Blob 的知识点介绍得非常完整清晰,本文通过四个问题来总结本文核心知识:
pingan8787
2020/06/08
2.9K0
Projects: 前端怎么处理二进制文件下载
type,默认值为 "",它代表了将会被放入到blob中的数组内容的MIME类型。 endings,默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个: "native",代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者 "transparent",代表会保持blob中保存的结束符不变
西南_张家辉
2021/02/02
1K0
从图片裁剪来聊聊前端二进制
首先判断window.navigator.msSaveOrOpenBlob是为了兼容IE(谁要兼容这 xxIE!!)
前端森林
2020/08/21
1.8K0
从图片裁剪来聊聊前端二进制
相关推荐
Protocol Buffers 在前端项目中的使用
更多 >
加入讨论
的问答专区 >
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
    本文部分代码块支持一键运行,欢迎体验
    本文部分代码块支持一键运行,欢迎体验