当前位置:编程学习 > JAVA >>

遇见Javascript类型数组

Typed Arrays(类型数组)这个概念,可能对很多人来说非常陌生,那么它是什么,又有什么用途呢?

之前的问题

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

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

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

定义

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

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

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


[html] // 创建一个8字节的ArrayBuffer 
var b = new ArrayBuffer(8); 
 
// 创建一个指向b的视图v1,采用Int32类型,开始于默认的字节索引0,直到缓冲区的末尾 
var v1 = new Int32Array(b); 
 
// 创建一个指向b的视图v2,采用Uint8类型,开始于字节索引2,直到缓冲区的末尾 
var v2 = new Uint8Array(b, 2); 
 
// 创建一个指向b的视图v3,采用Int16类型,开始于字节索引2,长度为2 
var v3 = new Int16Array(b, 2, 2); 
      // 创建一个8字节的ArrayBuffer
      var b = new ArrayBuffer(8);

      // 创建一个指向b的视图v1,采用Int32类型,开始于默认的字节索引0,直到缓冲区的末尾
      var v1 = new Int32Array(b);

      // 创建一个指向b的视图v2,采用Uint8类型,开始于字节索引2,直到缓冲区的末尾
      var v2 = new Uint8Array(b, 2);

      // 创建一个指向b的视图v3,采用Int16类型,开始于字节索引2,长度为2
      var v3 = new Int16Array(b, 2, 2);

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

变量的数据结构
        类型数组包括以下几种类型:


名称 大小(以字节为单位) 说明
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.3GCPU的平台上。我们运行这个测试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创建超酷图像灰度渐变效果http://www.zzzyk.com/kf/201204/126014.html 》这篇文章里就用到了imageData。

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

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

[html] view plaincopyprint?var canvas = document.getElementById('canvas');  var canvascanvasWidth  = canvas.width;  var canvascanvasHeight = canvas.height;  var ctx = canvas.getContext('2d');  var imageData = ctx.getImageData(0,0, canvasWidth, canvasHeight);     var buf =new ArrayBuffer(imageData.data.length);  var data =new Uint32Array(buf);     for(var y =0; y < canvasHeight;++y){      for(var x =0; x < canvasWidth;++x){          var value = x * y &0xff;             data[y * canvasWidth + x]=              (255   <<24)|    // alpha              (value <<16)|    // blue              (value <<  8)|    // green               value;            // red      }  }  var canvas = document.getElementById('canvas');
var canvasWidth  = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext('2d');
var imageData = ctx.getImageData(0,0, canvasWidth, canvasHeight);
 
var buf =n

补充:web前端 , JavaScript ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,