类型数组:在浏览器中处理二进制数据

更多HTML 5文章请查阅HTML 6在线网站http://www.html5online.com.cn

本文概述
        型数组是一个最近被使用到浏览器中的概念,它起源于在WebGL API中对于二进制数据进行有效处理的需求。一个类型数组代表一小段内存,可通过类型数组视图对该内存段中的数据进行查看。因为类型数组直接代表内存,所以JavaScript引擎可以直接通过它对内存进行操作,而不需要在使用前首先对数据进行转换。因此,在使用WebGL API或其他可用于处理二进制数据的API时,类型数组比JavaScript数组更加适用一些。
        类型数组视图类似于一个映射了类型数组所代表的内存区中的一段数据的JavaScript数组。根据数据类型,可以将类型数组视图分为很多种类、例如Float32Array、Float64Array、int32Array、Uint8Array或Uint8ClampedArray,其中Uint8ClampedArray专用于代替Canvas API中用于保存canvas元素中所有像素的像素数组。
        DataView是一种特殊的类型数组视图,用于存储多种类型的数据。DataView对象提供多种get/set方法,用于在类型数组所代表的内存区的任意位置存取任意类型的数据。当读写文件头或其他结构数据时,DataView对象比其他类型数组视图的作用更大一些。
类型数组的基本概念
类型数组视图
        为了使用类型数组,首先需要创建一个ArrayBuffer对象与一个类型数组视图。最简单的方法是通过指定的尺寸及数据类型来创建一个数据类型视图。
//类型数组视图的用法类似于标准JavaScript数组
var f64a = new Float64Array(8);
f64a[0] = 10;
f64a[1] = 20;
f64a[2] = f64a[0] + f64a[1];
        在HTML 5中,存在多种类型的类型数组视图,它们的创建与使用方法大致类似。在如下所示的代码中,我们创建所有种类的类型数组视图。
//浮点数数组
var f64 = new Float64Array(8);
var f32 = new Float32Array(16);
//有符号整型数组
var i32 = new Int32Array(16);
var i16 = new Int16Array(32);
var i8 = new Int8Array(64);
//无符号整型数组
var u32 = new Uint32Array(16);
var u16 = new Uint16Array(32);
var u8 = new Uint8Array(64);
var pixels = new Uint8ClampedArray(64);
        最后一种类型数组视图为一种比较特殊的类型数组视图,它的可使用值为从0到255,该数组专用于处理canvas元素中的所有像素数据。
        另一种创建类型数组视图的方法是首先创建一个ArrayBuffer对象,然后创建一个指向该缓存区对象的类型数组视图对象。
var ab = new ArrayBuffer(256); //256字节的ArrayBuffer缓存区对象
var faFull = new Uint8Array(ab);
var faFirstHalf = new Uint8Array(ab, 0, 128);
var faThirdQuarter = new Uint8Array(ab, 128, 64);
var faRest = new Uint8Array(ab, 192);
        你也可以将几种类型数组视图指向同一个ArrayBuffer缓存区对象。
var fa = new Float32Array(64);
var ba = new Uint8Array(fa.buffer, 0, Float32Array.BYTES_PER_ELEMENT);//fa数组中的第一个浮点数 
        在将类型数组视图进行复制时,最快的方法是使用类型数组视图的set方法。代码如下所示。
function memcpy(dst, dstOffset, src, srcOffset, length) {
    var dstU8 = new Uint8Array(dst, dstOffset, length);
    var srcU8 = new Uint8Array(src, srcOffset, length);
    dstU8.set(srcU8);
}; 
DataView
        为了使用一个包含了多种数据类型的ArrayBuffer缓存区,最简便的方法是使用DataView对象。假设我们使用一个文件,文件头中包含了一个8位无符号数据,后跟2个16位整数数据,文件内容为一个32位浮点数数组,可以通过使用DataView对象读取文件头,使用一个浮点数组类型的类型数组视图读取文件数据。
var dv = new DataView(buffer);
var vector_length = dv.getUint8(0);
var width = dv.getUint16(1); // 0+uint8 = 1字节偏移
var height = dv.getUint16(3); // 0+uint8+uint16 = 3字节偏移
var vectors = new Float32Array(width*height*vector_length);
for (var i=0, off=5; i<vectors.length; i++, off+=4) {
    vectors[i] = dv.getFloat32(off);
}
        在这段代码示例中,所有数据都是通过big- endian方式被存储在缓存区中的。如果数据是通过little-endian方式被存储的,你可以在getter函数中使用一个可选的littleEndian参数,方法如下所示。.
var width = dv.getUint16(1, true);
var height = dv.getUint16(3, true);.
vectors[i] = dv.getFloat32(off, true);
        DataView对象同时拥有一些将数据写入ArrayBuffer缓存区中的set方法,这些方法的使用方法与DataView对象的get方法的使用方法十分相似,代码如下所示:
dv.setInt32(0, 25, false); //在ArrayBuffer缓存区的第0字节到第25字节处使用big-endian方式存储32位整型数据
dv.setInt32(4, 25); //在ArrayBuffer缓存区的第4字节到第25字节处使用big-endian方式存储32位整型数据
dv.setFloat32(8,3, true); //在ArrayBuffer缓存区的第8字节到第3字节处使用little-endian方式存储32位浮点数据
关于数据存储方式
        此处所讲的big-endian数据存储方式或little-endian数据存储方式,是指在计算机内存中存储数据的字节排列顺序,其中big-endian方式是指低地址存放最高有效字节,而little-endian方式是指高地址存放最高有效字节。目前为止,在有些CPU中,使用big-endian方式来进行数据的存储,在有些CPU中,使用little-endian方式来进行数据的存储,在有些CPU中,可以通过设置来选择使用big-endian方式或使用little-endian方式来进行数据的存储。
        为什么我们需要关注数据的存储方式?原因很简单,当从磁盘或网络中读写数据时,必须指定数据的存储方式,以确保数据读写的正确性。在不断发展的网络世界中,必须同时支持这两种数据存储方式,从而能够处理所有来自服务器端或来自网络中其他位置的二进制数据。
使用类型数组的API
        接下来,我们介绍一些HTML 5中使用类型数组的API,包括WebGL、Canvas、Web Audio API、XMLHttpRequest、WebSocket、Web Workers、Media Source API与File API。从这些API中,你可以看出类型数组很适合被使用在处理多媒体数据或其他二进制数据的场合。
WebGL
        第一个使用类型数组的API是WebGL API、在该API中使用类型数组来缓存图像数据。为了保存WebGL缓存区对象中的数据,需要使用gl.bufferData()方法。
var floatArray = new Float32Array([1,2,3,4,5,6,7,8]);
gl.bufferData(gl.ARRAY_BUFFER, floatArray);
        类型数组也可以被用来存取纹理数据。在如下所示的代码中,在参数中通过类型数组来传递纹理数据。
var pixels = new Uint8Array(16*16*4); //16x16的RGBA图像
gl.texImage2D(
  gl.TEXTURE_2D, //图像类型(gl.TEXTURE_2D表示该图像是一个2D图像)
  0, //图像的详细程度
  gl.RGBA, //显卡内部的数据存储格式
  16, 16, //图像的宽度与高度
  0, //图像边框宽度
  gl.RGBA, //图像格式
  gl.UNSIGNED_BYTE, //组成图像的数据是无符号字节类型
  pixels //纹理图像数据
);
        在从WebGL上下文对象中读取像素数据时,也需要使用类型数组。
var pixels = new Uint8Array(320*240*4); //320x240的RGBA图像
gl.readPixels(0, 0, 320, 240, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
Canvas 2D
        最近,在Canvas API中开始使用类型数组。现在你可以使用类型数组来访问一个canvas元素中的所有像素,从而可以创建或编辑由canvas元素中所有像素组成的数组。
var imageData = ctx.getImageData(0,0, 200, 100);
var typedArray = imageData.data //data是一个Uint8ClampedArray数组
XMLHttpRequest2
        在HTML 5中,你可以在服务器端响应中接收一个类型数组,而不用再把一个响应字符串转换成为一个类型数组。当在多媒体API中直接抓取网络中的二进制文件时该方法非常有用。
        当需要获取服务器端的类型数组时,你需要将XMLHttpRequest对象的responseType属性值设置为“arraybuffer”。
xhr.responseType = 'arraybuffer';
        当从网络上下载二进制数据时,你必须知道服务器端数据的存储方式(big-endian方式或little-endian方式)。
文件API
        FileReader对象可以将文件内容读取到ArrayBuffer缓存区中,然后使用类型数组视图对象或DataView对象读取并操作ArrayBuffer缓存区中的数据。
reader.readAsArrayBuffer(file);
        同样地,你必须关注文件中数据的存储方式(big-endian方式或little-endian方式)。
audio元素或video元素
        最近,audio元素或video元素也可以使用类型数组。你可以直接在video元素的webkitSourceAppend方法的参数中使用一个包含了视频数据的类型数组。这使得video元素拥有了在当前视频中追加视频数据的能力。在插播广告、制作播放列表或其他需要在一个video元素中播放多个视频数据时,webkitSourceAppend方法将变得非常有用。
video.webkitSourceAppend(uint8Array);
在WebSocket API中使用二进制数据
在WebSocket API中,你同样可以使用类型数组。
socket.binaryType = 'arraybuffer';
设计
        最初,类型数组被用于在JavaScript语言中使用二进制数据,因此,类型数组视图所处理的数据的存储方式(big-endian方式或little-endian方式)均取决于客户端本地计算机中CPU所使用的数据存储方式。这种处理方法使JavaScript在实现类似将顶点数据传入显卡之类的处理时拥有最快的性能。
        后来,DataView被专用于处理文件或网络数据,这些数据通常拥有一个指定的数据存储方式,但是处理这些数据时不一定能拥有最好的性能。
        因此,我们应该使用类型数组视图来处理内存中的数据,使用DataView对象来处理文件或网络中的数据。现代JavaScript引擎已经为类型数组实现了大量的优化处理,使其在被进行数值计算时拥有非常好的性能。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值