谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64(下)

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
简介: 谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64(下)

谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64(上)https://developer.aliyun.com/article/1411385


4. ArrayBuffer


(1)ArrayBuffer

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。ArrayBuffer 的内容不能直接操作,只能通过 DataView 对象或 TypedArrray 对象来访问。这些对象用于读取和写入缓冲区内容。

ArrayBuffer 本身就是一个黑盒,不能直接读写所存储的数据,需要借助以下视图对象来读写:

  • TypedArray:用来生成内存的视图,通过9个构造函数,可以生成9种数据格式的视图。
  • DataViews:用来生成内存的视图,可以自定义格式和字节序。

11.webp.jpg

TypedArray视图和 DataView视图的区别主要是字节序,前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型。

那 ArrayBuffer 与 Blob 有啥区别呢?根据 ArrayBuffer 和 Blob 的特性,Blob 作为一个整体文件,适合用于传输;当需要对二进制数据进行操作时(比如要修改某一段数据时),就可以使用 ArrayBuffer。

下面来看看 ArrayBuffer 有哪些常用的方法和属性。

① new ArrayBuffer()

ArrayBuffer 可以通过以下方式生成:

javascript

复制代码

newArrayBuffer(bytelength)

ArrayBuffer()构造函数可以分配指定字节数量的缓冲区,其参数和返回值如下:

  • 参数:它接受一个参数,即 bytelength,表示要创建数组缓冲区的大小(以字节为单位。);
  • 返回值:返回一个新的指定大小的ArrayBuffer对象,内容初始化为0。

② ArrayBuffer.prototype.byteLength

ArrayBuffer 实例上有一个 byteLength 属性,它是一个只读属性,表示 ArrayBuffer 的 byte 的大小,在 ArrayBuffer 构造完成时生成,不可改变。来看例子:


const buffer = newArrayBuffer(16); 
console.log(buffer.byteLength);  // 16

③ ArrayBuffer.prototype.slice()

ArrayBuffer 实例上还有一个 slice 方法,该方法可以用来截取 ArrayBuffer 实例,它返回一个新的 ArrayBuffer ,它的内容是这个 ArrayBuffer 的字节副本,从 begin(包括),到 end(不包括)。来看例子:


const buffer = newArrayBuffer(16); 
console.log(buffer.slice(0, 8));  // 16

这里会从 buffer 对象上将前8个字节生成一个新的ArrayBuffer对象。这个方法实际上有两步操作,首先会分配一段指定长度的内存,然后拷贝原来ArrayBuffer对象的置顶部分。

④ ArrayBuffer.isView()

ArrayBuffer 上有一个 isView()方法,它的返回值是一个布尔值,如果参数是 ArrayBuffer 的视图实例则返回 true,例如类型数组对象或 DataView 对象;否则返回 false。简单来说,这个方法就是用来判断参数是否是 TypedArray 实例或者 DataView 实例:


const buffer = new ArrayBuffer(16);
ArrayBuffer.isView(buffer)   // false
const view = new Uint32Array(buffer);
ArrayBuffer.isView(view)     // true
(2)TypedArray

TypedArray 对象一共提供 9 种类型的视图,每一种视图都是一种构造函数。如下:

元素 类型化数组 字节 描述
Int8 Int8Array 1 8 位有符号整数
Uint8 Uint8Array 1 8 位无符号整数
Uint8C Uint8ClampedArray 1 8 位无符号整数
Int16 Int16Array 2 16 位有符号整数
Uint16 Uint16Array 2 16 位无符号整数
Int32 Int32Array 4 32 位有符号整数
Uint32 Uint32Array 4 32 位无符号整数
Float32 Float32Array 4 32 位浮点
Float64 Float64Array 8 64 位浮点

来看看这些都是什么意思:

  • **Uint8Array:**将 ArrayBuffer 中的每个字节视为一个整数,可能的值从 0 到 255 (一个字节等于 8 位)。 这样的值称为“8 位无符号整数”。
  • Uint16Array:将 ArrayBuffer 中任意两个字节视为一个整数,可能的值从 0 到 65535。 这样的值称为“16 位无符号整数”。
  • **Uint32Array:**将 ArrayBuffer 中任何四个字节视为一个整数,可能值从 0 到 4294967295,这样的值称为“32 位无符号整数”。

这些构造函数生成的对象统称为 TypedArray 对象。它们和正常的数组很类似,都有length 属性,都能用索引获取数组元素,所有数组的方法都可以在类型化数组上面使用。

那类型化数组和数组有什么区别呢?

  • 类型化数组的元素都是连续的,不会为空;
  • 类型化数组的所有成员的类型和格式相同;
  • 类型化数组元素默认值为 0;
  • 类型化数组本质上只是一个视图层,不会存储数据,数据都存储在更底层的 ArrayBuffer 对象中。

下面来看看 TypedArray 都有哪些常用的方法和属性。

① new TypedArray()

TypedArray 的语法如下(TypedArray只是一个概念,实际使用的是那9个对象):

javascript

复制代码

new Int8Array(length);
new Int8Array(typedArray);
new Int8Array(object);
new Int8Array(buffer [, byteOffset [, length]]);

可以看到,TypedArray 有多种用法,下面来分别看一下。

  • TypedArray(length):通过分配指定长度内容进行分配

javascript

复制代码

let view = new Int8Array(16);
view[0] = 10;
view[10] = 6;
console.log(view);

输出结果如下:5.webp (1).jpg这里就生成了一个 16个元素的 Int8Array 数组,除了手动赋值的元素,其他元素的初始值都是 0。

  • TypedArray(typeArray):接收一个视图实例作为参数

javascript

复制代码

const view = newInt8Array(newUint8Array(6));
view[0] = 10;view[3] = 6;console.log(view);

输出结果如下:67.webp.jpg

  • TypedArray(object):参数可以是一个普通数组

javascript

复制代码

const view = newInt8Array([1, 2, 3, 4, 5]);
view[0] = 10;view[3] = 6;console.log(view);

输出结果如下:68.webp.jpg需要注意,TypedArray视图会开辟一段新的内存,不会在原数组上建立内存。当然,这里创建的类型化数组也能转换回普通数组:

javascript

复制代码

Array.prototype.slice.call(view); // [10, 2, 3, 6, 5]
  • TypeArray(buffer [, byteOffset [, length]])

这种方式有三个参数,其中第一个参数是一个ArrayBuffer对象;第二个参数是视图开始的字节序号,默认从0开始,可选;第三个参数是视图包含的数据个数,默认直到本段内存区域结束。

javascript

复制代码

const buffer = newArrayBuffer(8);
const view1 = newInt32Array(buffer); 
const view2 = newInt32Array(buffer, 4); 
console.log(view1, view2);

输出结果如下:65.webp.jpg

BYTES_PER_ELEMENT

每种视图的构造函数都有一个 BYTES_PER_ELEMENT 属性,表示这种数据类型占据的字节数:

Int8Array.BYTES_PER_ELEMENT // 1
Uint8Array.BYTES_PER_ELEMENT // 1
Int16Array.BYTES_PER_ELEMENT // 2
Uint16Array.BYTES_PER_ELEMENT // 2
Int32Array.BYTES_PER_ELEMENT // 4
Uint32Array.BYTES_PER_ELEMENT // 4
Float32Array.BYTES_PER_ELEMENT // 4
Float64Array.BYTES_PER_ELEMENT // 8

BYTES_PER_ELEMENT 属性也可以在类型化数组的实例上获取:

const buffer = new ArrayBuffer(16); 
const view = new Uint32Array(buffer); 
console.log(Uint32Array.BYTES_PER_ELEMENT); // 4

TypedArray.prototype.buffer

TypedArray 实例的 buffer 属性会返回内存中对应的 ArrayBuffer对象,只读属性。

javascript

复制代码

const a = newUint32Array(8);
const b = newInt32Array(a.buffer); 
console.log(a, b);

输出结果如下:66.webp.jpg

TypedArray.prototype.slice()

TypeArray 实例的 slice方法可以返回一个指定位置的新的 TypedArray实例。

javascript

复制代码

const view = newInt16Array(8);
console.log(view.slice(0 ,5));

输出结果如下:345.webp.jpg

⑤ byteLength 和 length

  • byteLength:返回 TypedArray 占据的内存长度,单位为字节;
  • length:返回 TypedArray 元素个数;

javascript

复制代码

const view = newInt16Array(8);
view.length;      // 8view.byteLength;  // 16

(3)DataView

说完 ArrayBuffer,下面来看看另一种操作 ArrayBuffer 的方式:DataView。DataView 视图是一个可以从 二进制 ArrayBuffer 对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序问题。

DataView视图提供更多操作选项,而且支持设定字节序。本来,在设计目的上,ArrayBuffer对象的各种TypedArray视图,是用来向网卡、声卡之类的本机设备传送数据,所以使用本机的字节序就可以了;而DataView视图的设计目的,是用来处理网络设备传来的数据,所以大端字节序或小端字节序是可以自行设定的。

① new DataView()

DataView视图可以通过构造函数来创建,它的参数是一个ArrayBuffer对象,生成视图。其语法如下:

javascript

复制代码

newDataView(buffer [, byteOffset [, byteLength]])

其有三个参数:

  • buffer:一个已经存在的 ArrayBuffer 对象,DataView 对象的数据源。
  • byteOffset:可选,此 DataView 对象的第一个字节在 buffer 中的字节偏移。如果未指定,则默认从第一个字节开始。
  • byteLength:可选,此 DataView 对象的字节长度。如果未指定,这个视图的长度将匹配 buffer 的长度。

来看一个例子:

javascript

复制代码

const buffer = newArrayBuffer(16);
const view = newDataView(buffer);
console.log(view);

打印结果如下:333.webp.jpg

② buffer、byteLength、byteOffset

DataView实例有以下常用属性:

  • buffer:返回对应的ArrayBuffer对象;
  • byteLength:返回占据的内存字节长度;
  • byteOffset:返回当前视图从对应的ArrayBuffer对象的哪个字节开始。

javascript

复制代码

const buffer = newArrayBuffer(16);
const view = newDataView(buffer);
view.buffer;view.byteLength;view.byteOffset;

打印结果如下:334.webp.jpg

③ 读取内存

DataView 实例提供了以下方法来读取内存,它们的参数都是一个字节序号,表示开始读取的字节位置:

  • getInt8:读取1个字节,返回一个8位整数。
  • getUint8:读取1个字节,返回一个无符号的8位整数。
  • getInt16:读取2个字节,返回一个16位整数。
  • getUint16:读取2个字节,返回一个无符号的16位整数。
  • getInt32:读取4个字节,返回一个32位整数。
  • getUint32:读取4个字节,返回一个无符号的32位整数。
  • getFloat32:读取4个字节,返回一个32位浮点数。
  • getFloat64:读取8个字节,返回一个64位浮点数。

下面来看一个例子:

const buffer = new ArrayBuffer(24);
const view = new DataView(buffer);
// 从第1个字节读取一个8位无符号整数
const view1 = view.getUint8(0);
// 从第2个字节读取一个16位无符号整数
const view2 = view.getUint16(1);
// 从第4个字节读取一个16位无符号整数
const view3 = view.getUint16(3);

④ 写入内存

DataView 实例提供了以下方法来写入内存,它们都接受两个参数,第一个参数表示开始写入数据的字节序号,第二个参数为写入的数据:

  • setInt8:写入1个字节的8位整数。
  • setUint8:写入1个字节的8位无符号整数。
  • setInt16:写入2个字节的16位整数。
  • setUint16:写入2个字节的16位无符号整数。
  • setInt32:写入4个字节的32位整数。
  • setUint32:写入4个字节的32位无符号整数。
  • setFloat32:写入4个字节的32位浮点数。
  • setFloat64:写入8个字节的64位浮点数。


5. Object URL



Object URL(MDN定义名称)又称Blob URL(W3C定义名称),是HTML5中的新标准。它是一个用来表示File Object 或Blob Object 的URL。在网页中,我们可能会看到过这种形式的 Blob URL:345.webp (1).jpg其实Blob URL/Object URL 是一种伪协议,允许将 Blob 和 File 对象用作图像、二进制数据下载链接等的 URL 源。

对于 Blob/File 对象,可以使用 URL构造函数的 createObjectURL() 方法创建将给出的对象的 URL。这个 URL 对象表示指定的 File 对象或 Blob 对象。我们可以在</code> 标签中或者 <code><a></code> 和 <code><link></code> 标签的 <code>href</code> 属性中使用这个 URL。</div><div>来看一个简单的例子,首先定义一个文件上传的 input 和一个 图片预览的 img:</div><div data-card-type="block" data-ready-card="codeblock" data-card-value="data:%7B%22mode%22%3A%22plain%22%2C%22code%22%3A%22%3Cinput%20type%3D%5C%22file%5C%22%20id%3D%5C%22fileInput%5C%22%20%2F%3E%5Cn%5Cn%3Cimg%20id%3D%5C%22preview%5C%22%20%2F%3E%5Cn%22%2C%22heightLimit%22%3Atrue%2C%22margin%22%3Atrue%2C%22id%22%3A%22WvK9I%22%7D"></div><div>再来使用 <code>URL.createObjectURL()</code> 将File 对象转化为一个 URL:</div><div data-card-type="block" data-ready-card="codeblock" data-card-value="data:%7B%22mode%22%3A%22plain%22%2C%22code%22%3A%22const%20fileInput%20%3D%20document.getElementById(%5C%22fileInput%5C%22)%3B%5Cnconst%20preview%20%3D%20document.getElementById(%5C%22preview%5C%22)%3B%5Cn%5CnfileInput.onchange%20%3D%20(e)%20%3D%3E%20%7B%5Cn%20%20preview.src%20%3D%20URL.createObjectURL(e.target.files%5B0%5D)%3B%5Cn%20%20console.log(preview.src)%3B%5Cn%7D%3B%5Cn%22%2C%22heightLimit%22%3Atrue%2C%22margin%22%3Atrue%2C%22id%22%3A%22jPVfx%22%7D"></div><div>可以看到,上传的图片转化成了一个 URL,并显示在了屏幕上:<span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2Fyjbvedpo6nmku_74c278cd195a492ba9cc04403770b587.jpg%22%2C%22originWidth%22%3A1512%2C%22originHeight%22%3A302%2C%22name%22%3A%22234.webp.jpg%22%2C%22size%22%3A71669%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A1512%2C%22height%22%3A302%7D"></span>那这个 API 有什么意义呢?可以将Blob/File对象转化为URL,通过这个URL 就可以实现文件下载或者图片显示等。</div><div>当我们使用<code>createObjectURL()</code>方法创建一个data URL 时,就需要使用<code>revokeObjectURL()</code>方法从内存中清除它来释放内存。虽然浏览器会在文档卸载时自动释放 Data URL,但为了提高性能,我们应该使用<code>createObjectURL()</code>来手动释放它。<code>revokeObjectURL()</code>方法接受一个Data URL 作为其参数,返回<code>undefined</code>。下面来看一个例子:</div><div><span>javascript</span></div><div>复制代码</div><pre><code><span>const</span> objUrl = <span>URL</span>.<span>createObjectURL</span>(<span>new</span> <span>File</span>([<span>""</span>], <span>"filename"</span>)); <span>console</span>.<span>log</span>(objUrl); <span>URL</span>.<span>revokeObjectURL</span>(objUrl); </code></pre><div><br /></div><h2 id="fCvuK">6. Base64</h2><div><br /></div><div>Base64 是一种基于64个可打印字符来表示二进制数据的表示方法。Base64 编码普遍应用于需要通过被设计为处理文本数据的媒介上储存和传输二进制数据而需要编码该二进制数据的场景。这样是为了保证数据的完整并且不用在传输过程中修改这些数据。</div><div>在 JavaScript 中,有两个函数被分别用来处理解码和编码 <em>base64</em> 字符串:</div><ul><li><code>atob()</code>:解码,解码一个 Base64 字符串;</li><li><code>btoa()</code>:编码,从一个字符串或者二进制数据编码一个 Base64 字符串。</li></ul><div><span>javascript</span></div><div>复制代码</div><pre><code><span>btoa</span>(<span>"JavaScript"</span>)       <span>// 'SmF2YVNjcmlwdA=='</span> <span>atob</span>(<span>'SmF2YVNjcmlwdA=='</span>) <span>// 'JavaScript'</span> </code></pre><div>那 base64 的实际应用场景有哪些呢?其实多数场景就是基于Data URL的。比如,使用<code>toDataURL()</code>方法把 canvas 画布内容生成 base64 编码格式的图片:</div><div><span>javascript</span></div><div>复制代码</div><pre><code><span>const</span> canvas = <span>document</span>.<span>getElementById</span>(<span>'canvas'</span>);  <span>const</span> ctx = canvas.<span>getContext</span>(<span>"2d"</span>); <span>const</span> dataUrl = canvas.<span>toDataURL</span>(); </code></pre><div>除此之外,还可以使用<code>readAsDataURL()</code>方法把上传的文件转为base64格式的data URI,比如上传头像展示或者编辑:</div><div data-card-type="block" data-ready-card="codeblock" data-card-value="data:%7B%22mode%22%3A%22plain%22%2C%22code%22%3A%22%3Cinput%20type%3D%5C%22file%5C%22%20id%3D%5C%22fileInput%5C%22%20%2F%3E%5Cn%5Cn%3Cimg%20id%3D%5C%22preview%5C%22%20%2F%3E%5Cn%22%2C%22heightLimit%22%3Atrue%2C%22margin%22%3Atrue%2C%22id%22%3A%22e4N6W%22%7D"></div><div data-card-type="block" data-ready-card="codeblock" data-card-value="data:%7B%22mode%22%3A%22plain%22%2C%22code%22%3A%22const%20fileInput%20%3D%20document.getElementById(%5C%22fileInput%5C%22)%3B%5Cnconst%20preview%20%3D%20document.getElementById(%5C%22preview%5C%22)%3B%5Cnconst%20reader%20%3D%20new%20FileReader()%3B%5Cn%5CnfileInput.onchange%20%3D%20(e)%20%3D%3E%20%7B%5Cn%20%20reader.readAsDataURL(e.target.files%5B0%5D)%3B%5Cn%7D%3B%5Cn%5Cnreader.onload%20%3D%20(e)%20%3D%3E%20%7B%5Cn%20%20preview.src%20%3D%20e.target.result%3B%5Cn%20%20console.log(e.target.result)%3B%5Cn%7D%3B%5Cn%22%2C%22heightLimit%22%3Atrue%2C%22margin%22%3Atrue%2C%22id%22%3A%22vWiXf%22%7D"></div><div>效果如下,将图片(二进制数据)转化为可打印的字符,也便于数据的传输:<span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2Fyjbvedpo6nmku_b6fb6206519f44aa9ff04587760ceb95.jpg%22%2C%22originWidth%22%3A1500%2C%22originHeight%22%3A775%2C%22name%22%3A%22456.webp.jpg%22%2C%22size%22%3A648145%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A1500%2C%22height%22%3A775%7D"></span>另外,一些小的图片都可以使用 base64 格式进行展示,<code>img</code>标签和<code>background</code>的 <code>url</code> 属性都支持使用base64 格式的图片,这样做也可以减少 HTTP 请求。</div><div><br /></div><h2 id="BcZKS">7. 格式转化</h2><div><br /></div><div>看完这些基本的概念和使用,下面就来看看常用的格式之间是如何转换的。</div><h3 id="9swqL">(1)ArrayBuffer → blob</h3><div><span>javascript</span></div><div>复制代码</div><pre><code><span>const</span> blob = <span>new</span> <span>Blob</span>([<span>new</span> <span>Uint8Array</span>(buffer, byteOffset, length)]); </code></pre><h3 id="mJ7Q2">(2)ArrayBuffer → base64</h3><div><span>javascript</span></div><div>复制代码</div><pre><code><span>const</span> base64 = <span>btoa</span>(<span>String</span>.<span>fromCharCode</span>.<span>apply</span>(<span>null</span>, <span>new</span> <span>Uint8Array</span>(arrayBuffer))); </code></pre><h3 id="vlqQF">(3)base64 → blob</h3><div data-card-type="block" data-ready-card="codeblock" data-card-value="data:%7B%22mode%22%3A%22plain%22%2C%22code%22%3A%22const%20base64toBlob%20%3D%20(base64Data%2C%20contentType%2C%20sliceSize)%20%3D%3E%20%7B%5Cn%20%20const%20byteCharacters%20%3D%20atob(base64Data)%3B%5Cn%20%20const%20byteArrays%20%3D%20%5B%5D%3B%5Cn%5Cn%20%20for%20(let%20offset%20%3D%200%3B%20offset%20%3C%20byteCharacters.length%3B%20offset%20%2B%3D%20sliceSize)%20%7B%5Cn%20%20%20%20const%20slice%20%3D%20byteCharacters.slice(offset%2C%20offset%20%2B%20sliceSize)%3B%5Cn%5Cn%20%20%20%20const%20byteNumbers%20%3D%20new%20Array(slice.length)%3B%5Cn%20%20%20%20for%20(let%20i%20%3D%200%3B%20i%20%3C%20slice.length%3B%20i%2B%2B)%20%7B%5Cn%20%20%20%20%20%20byteNumbers%5Bi%5D%20%3D%20slice.charCodeAt(i)%3B%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20const%20byteArray%20%3D%20new%20Uint8Array(byteNumbers)%3B%5Cn%20%20%20%20byteArrays.push(byteArray)%3B%5Cn%20%20%7D%5Cn%5Cn%20%20const%20blob%20%3D%20new%20Blob(byteArrays%2C%20%7Btype%3A%20contentType%7D)%3B%5Cn%20%20return%20blob%3B%5Cn%7D%5Cn%22%2C%22heightLimit%22%3Atrue%2C%22margin%22%3Atrue%2C%22id%22%3A%22YsF9X%22%7D"></div><div><code></code></div><h3 id="hlatX">(4)blob → ArrayBuffer</h3><div data-card-type="block" data-ready-card="codeblock" data-card-value="data:%7B%22mode%22%3A%22plain%22%2C%22code%22%3A%22function%20blobToArrayBuffer(blob)%20%7B%20%5Cn%20%20return%20new%20Promise((resolve%2C%20reject)%20%3D%3E%20%7B%5Cn%20%20%20%20%20%20const%20reader%20%3D%20new%20FileReader()%3B%5Cn%20%20%20%20%20%20reader.onload%20%3D%20()%20%3D%3E%20resolve(reader.result)%3B%5Cn%20%20%20%20%20%20reader.onerror%20%3D%20()%20%3D%3E%20reject%3B%5Cn%20%20%20%20%20%20reader.readAsArrayBuffer(blob)%3B%5Cn%20%20%7D)%3B%5Cn%7D%5Cn%22%2C%22heightLimit%22%3Atrue%2C%22margin%22%3Atrue%2C%22id%22%3A%22Jn3SE%22%7D"></div><h3 id="XkvQk">(5)blob → base64</h3><div data-card-type="block" data-ready-card="codeblock" data-card-value="data:%7B%22mode%22%3A%22plain%22%2C%22code%22%3A%22function%20blobToBase64(blob)%20%7B%5Cn%20%20return%20new%20Promise((resolve)%20%3D%3E%20%7B%5Cn%20%20%20%20const%20reader%20%3D%20new%20FileReader()%3B%5Cn%20%20%20%20reader.onloadend%20%3D%20()%20%3D%3E%20resolve(reader.result)%3B%5Cn%20%20%20%20reader.readAsDataURL(blob)%3B%5Cn%20%20%7D)%3B%5Cn%7D%5Cn%22%2C%22heightLimit%22%3Atrue%2C%22margin%22%3Atrue%2C%22id%22%3A%22w3W3l%22%7D"></div><h3 id="ZW56H">(6)blob → Object URL</h3><div><span><br /></span></div><pre><code><span>const</span> objectUrl = <span>URL</span>.<span>createObjectURL</span>(blob);</code></pre><div><br /></div>

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
相关文章
|
4月前
|
存储 JavaScript 前端开发
JS上传文件(base64字符串和二进制文件流)
这篇文章介绍了两种JavaScript文件上传的方法:使用FileReader对象将文件读取为base64字符串上传,以及使用FormData对象以二进制文件流的形式上传文件,包括如何处理文件选择、读取和上传的详细代码示例。
541 2
JS上传文件(base64字符串和二进制文件流)
|
4月前
|
JavaScript 前端开发
JS - 如何上传 Base64 编码的图片
本文展示了如何将Base64编码的图片在前端转换为Blob对象,并使用`FormData`上传到服务器端的方法。
210 0
|
5月前
|
JavaScript
js中readAsDataURL的意思,可以用于浏览器预览图像文件或者转成base64字符串
js中readAsDataURL的意思,可以用于浏览器预览图像文件或者转成base64字符串
js中readAsDataURL的意思,可以用于浏览器预览图像文件或者转成base64字符串
|
5月前
|
存储 资源调度 前端开发
JavaScript 使用axios库发送 post请求给后端, 给定base64格式的字符串数据和一些其他参数, 使用表单方式提交, 并使用onUploadProgress显示进度
使用 Axios 发送包含 Base64 数据和其他参数的 POST 请求时,可以通过 `onUploadProgress` 监听上传进度。由于整个请求体被视为一个单元,所以进度可能不够精确,但可以模拟进度反馈。前端示例代码展示如何创建一个包含 Base64 图片数据和额外参数的 `FormData` 对象,并在上传时更新进度条。后端使用如 Express 和 Multer 可处理 Base64 数据。注意,实际进度可能不如文件上传精确,显示简单加载状态可能更合适。
|
5月前
|
JavaScript 前端开发
vitepress初始化安装,最全 “vitepress > @docsearch/js > @docsearch/react > ,ENOENT: no such file or
vitepress初始化安装,最全 “vitepress > @docsearch/js > @docsearch/react > ,ENOENT: no such file or
|
7月前
|
前端开发 JavaScript PHP
解决在页面中无法获取qrcode.js生成的base64的图片
该文档介绍了如何解决在部分安卓手机上无法正确加载二维码图片的问题。之前的方法是使用qrcode.js生成二维码,然后与背景图结合用canvas绘制海报,但在某些安卓设备上遇到onload事件不触发的问题。
135 2
|
7月前
|
编解码 JavaScript 前端开发
【专栏】介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例
【4月更文挑战第29天】本文介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例。Base64编码将24位二进制数据转换为32位可打印字符,用“=”作填充。文中展示了各语言的编码解码代码,帮助开发者理解并应用于实际项目。
169 1
|
1月前
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
29 1
JavaScript中的原型 保姆级文章一文搞懂
|
5月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
107 2
|
1月前
JS+CSS3文章内容背景黑白切换源码
JS+CSS3文章内容背景黑白切换源码是一款基于JS+CSS3制作的简单网页文章文字内容背景颜色黑白切换效果。
21 0