`
mixer_a
  • 浏览: 369268 次
社区版块
存档分类
最新评论

遇见Javascript类型数组(Typed Array)

 
阅读更多

我在Chrome最新动态里提到了Typed Arrays(Typed Array,类型数组)这个概念,可能对很多人来说非常陌生,那么它是什么,又有什么用途呢?

之前的问题

Web应用程序变得越来越强大,例如新增了音视频处理、WebSocket等多个功能特性。毫无疑问,如果Javascript能够快速方便的操作原始二进制数据会相当的有用。过去,我们必须要把原始数据当作字符串来处理,并且使用charCodeAt方法来从数据缓冲区中读取字节。

但是这种方法需要多次转换数据(尤其在二进制数据不是字节格式的数据时,例如32位整数或者浮点数),所以非常慢而且容易出错。

Javascript需要一种机制来更有效的访问原始的二进制数据,由此产生了类型数组。

定义

其实除了Javascript,类型数组在其他很多语言中也有。它是一种数组,只有一种变量的类型。例如,一个float类型的数组将只包含浮点数而不能混用字符串和浮点数。此外,一个类型数组在初始化后不能改变大小。它看起来形式和普通Javascript数组很像,但是数据格式是一致和同一类型的(例如声音或者像素点的缓冲数据)。

类型数组的规范参见这里。这个规范实质上定义了一种arrayBuffer类型,相当于一个普通的定长二进制缓冲区。我们不能直接访问和操作arrayBuffer的内容,而需要类型数组来创建arrayBuffer的视图(从技术上来说,类型数组等同于arrayBuffer,因为它们本质上是一样的)。例如,要访问32位有符号整数数组作为缓冲区,会创建一个Int32Array的类型数组来指向arrayBuffer

多个类型数组视图可以指向同一个arrayBuffer,采用不同的类型、不同的长度以及不同的位移。例如下面的代码:

上述代码里变量的数据结构如下所示。


变量的数据结构

类型数组包括以下几种类型:

名称

大小 (以字节为单位)

说明

Int8Array

1

8位有符号整数

Uint8Array

1

8位无符号整数

Int16Array

2

16位有符号整数

Uint16Array

2

16位无符号整数

Int32Array

4

32位有符号整数

Uint32Array

4

32位无符号整数

Float32Array

4

32位浮点数

Float64Array

8

64位浮点数

类型数组实际上目前是作为WebGL的一部分来实现的(和它相关的还有File API),但是它可以用在任何地方。

下面我们来谈谈类型数组的优点和用途。

优点

1、 性能优秀

所有类型数组相关的文档都提到的重要一点是,类型数组比传统数组快的多,具有非常好的性能。因为类型数组实际上是作为一个固定的内存块来进行访问的,而传统的普通Javascript数组使用的是Hash查找方式(因为元素长度不定)。

这里有一个简单的测试结果,在Firefox4 Beta1版本,我们对比了一个普通数组和Float32Array数组在操作1亿个元素时每种操作所花费的时间。这个测试运行在Win7 64位、4G内存和Intel双核1.3G CPU的平台上。我们运行这个测试8次并使用其中最慢的一个时间。需要指出的是,普通Javascript数组的写入操作经常花费超过10秒钟,这会导致出现运行缓慢的脚本对话框。

操作

普通数组

Float32Array

8947

1455

1948

1109

循环复制

>10,000

1969

片段复制

1125

503

下面我们有一个关于普通数组、类型数组(arrayBuffer)以及imageData之间性能的比较,可以看到arrayBuffer会快得多。


性能优异的arrayBuffer

其实在类型数组之前,Javascript也支持二进制字节的数组,这就是imageData。imageData是Canvas元素2D上下文环境里定义的数据类型。当在Canvas 2D里调用getImageData或者createImageData方法时就创建了imageData。imageData的data属性是一个字节数组,它实际大小是图片宽*高的四倍(因为每个像素有R、G、B、A四个通道)。之前我们在《用HTML5创建超酷图像灰度渐变效果》这篇文章里就用到了imageData。

从图表数据来看,imageData和arrayBuffer在多个浏览器里创建的性能远远高于普通的数组(数据来源)。不过这里有一个问题,后面将会提到。

可以想见,因为优秀的性能表现,类型数组可以广泛的应用于Javascript图像以及视频的处理和压缩,还有一些需要复杂运算的场景例如MD5计算中,让功能可以更快速更高效的完成。例如我们先把imageData转换为类型数组以换取更快的执行速度,如下面的代码:

另外一方面,因为类型数组可以显著增加HTML5 Canvas 2D Web App的性能,所以这一特性对于使用HTML5来创建Web游戏的开发者会非常重要

下面是两个使用类型数组的示例。

第一个是Energy2D的演示,用于对比普通数组和类型数组的性能,大家可以自行体验。


Energy2D演示

第二个示例是使用类型数组、FileAPI以及Web Workers实现的SHA1在线计算器,它的性能相当出色。正是在类型数组的支持下,Javascript执行SHA1、MD5这样复杂运算的速度变得越来越快。

类型数组支持的在线SHA1计算器

2、 二进制支持

上文曾经提到类型数组最主要的特点是支持二进制数据。的确,现在HTMl5的许多API涉及音视频和实时通信,这些功能经常依赖于二进制文件格式,例如MP3音频、MP4视频和PNG图像。二进制格式对于减少带宽,提高性能,以及与现有文件格式互相转换来说非常重要。

类型数组使得Web应用可以使用多种二进制文件格式和直接操作文件的二进制内容,例如从现有的媒体文件中提取数据

IE10上,已经提供了类型数组的支持(支持WebGL其实是微软非常纠结的事情)。我们可以看看微软所提供的二进制文件检测器的例子


在这个示例里,我们可以获取音乐文件的ID3头,视频文件的原始字节数据,以及附加文件的格式。它的核心代码如下:

页面上文件的二进制格式输出就是用这段代码实现的。

具体应用

这里有一个使用类型数组在Canvas图像和二进制数据之间互相转换,然后通过WebSocket发送的示例。作者提到“在我实现二进制WebSocket示例时,我学习了很多Javascript类型数组的知识,了解了如何把对象转换为二进制数据。我写了一个示例来获取Canvas图像数据,并且把它通过二进制的WebSocket连接发送出去。WebSocket服务器获取图像数据,然后把它发送给所有连接的客户端(宇捷:这让我想起了最近国外非常火爆的超人气应用DrawSomething-你画我猜,我们可以用这种方式实现类似的WebApp),然后客户端再把Canvas数据还原为PNG图片。采用这种方式发送图像数据比起base64编码来更有效率(数据小33%,而且更利于序列化和存储)。”

创造了历史的应用-你画我猜

WebSocket支持二进制数据传输,对于WebSocket服务器来说,使用二进制数据会比UTF-8更为简单,不过现在浏览器支持方面还有问题。

示例里实现将Canvas数据转换为二进制格式的代码如下:

而把二进制数据还原为图像的代码如下,请注意我们不能直接从arrayBuffer获取数据直接放到Canvas中。

在Adobe的官网上,也有一个类似的完整示例:《Real Time Data Exchange in HTML5 with WebSocket》。可以看到里面利用类型数组发送图片的代码如下:

疑问

理论上来看,类型数组的性能毫无疑问比普通数组更快,但是根据《现代浏览器里类型数组的性能》一文中的评测,可以看到某些操作和某些浏览器下,类型数组的性能反而更低,另外imageData和ArrayBuffer的性能在同一浏览器中还有不同的表现。这个现象让人困惑,因为imageData和ArrayBuffer其实就是为了性能敏感的功能诞生的,理论上能够提供更快的读取和写入速度。这有极大可能是目前浏览器厂商对于二进制数组优化不足造成的。我希望浏览器未来对于类型数组能有更好的支持。


某些操作和浏览器下,类型数组性能反而更低

总结

随着HTML5 Canvas、WebSocket等新特性的出现,WebApp能做的事情越来越多,同时Web App对于性能要求也越来越高,Javascript类型数组正是在这种情况下应运而生的。随着IE、Chrome、Opera等主流浏览器逐步提供对它的全面支持,以及可预期的性能优化,它将会发挥越来越重要的作用。

附:类型数组的浏览器支持情况

转载请注明:来自蒋宇捷的博客

分享到:
评论

相关推荐

    concat-typed-array:连接n个类型数组

    连续类型数组 连接n个类型数组。 基于。 安装 npm install concat-typed-array 用法 import concatTypedArray from "concat-typed-array" ; concatTypedArray ( Uint8Array , Uint8Array . of ( 1 , 2 ) , Uint8...

    typed-morph:用于处理 Javascript 类型数组的高阶函数(map、reduce、filter)

    用于处理 Javascript 类型数组的高阶函数(map、reduce、filter)。 它们不使用中间数组进行链接,而是利用。 安装 npm i typed-morph 用法 地图 var wrap = require ( 'typed-morph' ) ; var elements = new Uint...

    javascript中的array数组使用技巧

    值得注意的是,虽然JavaScript数组在某些方面表现得与传统意义上的数组类似,但它们实际上是基于对象实现的,所以对于需要严格保证类型或操作性能的场景,可能需要使用其他数据结构,如Typed Arrays或collections...

    typed-array:验证值是否为类型化数组

    类型数组 验证值是否为。安装$ npm install validate.io-typed-array 要在浏览器中使用,请使用 。用法 var isTypedArray = require ( 'validate.io-typed-array' ) ;isTypedArray( 值 ) 验证值是否为。 var bool = ...

    is-typed-array

    TypedArray包含了一系列不同的数组类型,比如Int8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array、Float64Array等,每种类型都对应不同的数据宽度。 使用is-typed-array库...

    使用类型化数组有效地处理柱状数据

    与传统的JavaScript数组相比,类型化数组有以下几个显著优势: 1. **性能提升**:由于类型化数组的元素类型固定,它们在内存中的布局更为紧凑,因此读写速度更快,特别是在处理大量数据时。 2. **内存效率**:传统...

    JavaScript 数组的进化与性能分析

    总的来说,JavaScript数组从早期的哈希映射实现发展到现在,通过优化和引入类型化数组,极大地提高了性能和效率,尤其是在处理大量数据和高性能场景下。尽管JavaScript数组在实现上与传统语言有所不同,但通过利用...

    bodec:使用类型数组的二进制操作

    "bodec" 是一个库,专门设计用于处理类型数组(Typed Arrays),使得二进制操作变得简单易行。类型数组是JavaScript中高效处理原始二进制数据的一种方式,它允许我们直接在内存级别操作数据,避免了不必要的字符串...

    typed-array-number-function:在广播数字参数时将函数应用于每个类型的数组元素

    类型数组编号函数 在广播数字参数时,对每个元素应用一个函数。 安装 $ npm install compute-typed-array-number-function 要在浏览器中使用,请使用 。 用法 var arrayfun = require ( 'compute-typed-array-...

    eval-serialize-typed-array:序列化类型化数组以进行动态代码评估

    类型化数组序列化 序列化以进行动态代码评估。 安装 $ npm install eval-serialize-typed-array 用法 var serialize = require ( 'eval-serialize-typed-array' ) ; 序列化(值) 序列化以进行动态代码评估。 ...

    iTyped超级简单的Javascript动画打字效果没有任何依赖

    标题和描述提到了"iTyped",这是一个基于JavaScript的库,用于创建动态的、类似打字机效果的文本动画。"没有任何依赖"意味着这个库不需要其他外部库或框架的支持,比如jQuery或者React,可以独立运行。 **iTyped库...

    typed-array-function:将一个函数应用于每个类型化的数组元素

    类型化数组函数 将函数应用于每个元素。 安装 $ npm install compute-typed-array-function 要在浏览器中使用,请使用 。 用法 var arrayfun = require ( 'compute-typed-array-function' ) ; arrayfun(fcn,......

    ie11兼容es6语法资源包

    5. **解构赋值(Destructuring)**:可以从数组或对象中快速提取值,进行赋值。 6. **Promise**:用于处理异步操作,解决回调地狱问题,使异步代码更加清晰和易于管理。 在描述中提到的两个关键文件,是实现IE11...

    main_half_javascript_半精度浮点数_Uint8Array_

    1. **Uint8Array**: 这是一个 typed array 类型,用于表示无符号8位整数的固定大小数组。可以使用它来访问和操作二进制数据流中的每个字节。 2. **转换函数**: 为了从`Uint8Array`读取或写入半精度浮点数,你需要...

    webgl-reference-card-1_0

    - **功能**:创建一个新的 Typed Array 并复制 JavaScript 数组或其他 Typed Array 的数据到新的 ArrayBuffer。 - **`ViewType(ArrayBuffer buffer, [optional] ulong byteOffset, [optional] ulong length)`** ...

    前端项目-typed.js.zip

    3. **API使用**:Typed.js提供了一系列可定制的选项和方法,如`strings`定义要显示的文本数组,`typeSpeed`控制打字速度,`backSpeed`设定删除速度,`loop`决定是否循环播放等。开发者可以通过这些API调整动画效果以...

    JavaScript 类型的包装对象(Typed Wrappers)

    在JavaScript中,存在着一套特殊的对象类型,被称为“类型包装对象”(Typed Wrappers),这组对象包括了Boolean、Number、String以及Object和Array的包装版本。类型包装对象的主要功能是在需要对基本类型值进行对象...

    控制台打印文字效果js插件-typed.js

    然后,通过JavaScript代码创建一个`Typed`实例,并配置相应的选项,如字符串数组(要打印的文字)、速度、回删速度、暂停时间等。 ```html <script src="https://code.jquery.com/jquery-3.x.min.js"></script> ...

    meteor-crypto-lib-typedarrays:来自CryptoJS的类型化数组组件

    流星-crypto-lib-typedarrays 来自类型化数组组件。相依性 。安装在您的项目文件夹中运行: $ meteor add incocode:crypto-lib-typedarrays例子使用SHA256编码文件: function sha256Blob ( blob ) { return new ...

Global site tag (gtag.js) - Google Analytics