有没有办法测试两个JavaScript ArrayBuffers是否相等?我想为消息编写方法编写测试。我找到的唯一方法是将ArrayBuffer转换为字符串然后进行比较。我错过了什么吗?
以下代码给出了错误,即使我认为它应该是真的:
(function() {
'use strict';
/* Fill buffer with data of Verse header and user_auth
* command */
var buf_pos = 0;
var name_len = 6
var message_len = 4 + 1 + 1 + 1 + name_len + 1;
var buf = new ArrayBuffer(message_len);
var view = new DataView(buf);
/* Verse header starts with version */
view.setUint8(buf_pos, 1 << 4); /* First 4 bits are reserved for version of protocol */
buf_pos += 2;
/* The lenght of the message */
view.setUint16(buf_pos, message_len);
buf_pos += 2;
buf_pos = 0;
var buf2 = new ArrayBuffer(message_len);
var view2 = new DataView(buf);
/* Verse header starts with version */
view2.setUint8(buf_pos, 1 << 4); /* First 4 bits are reserved for version of protocol */
buf_pos += 2;
/* The lenght of the message */
view2.setUint16(buf_pos, message_len);
buf_pos += 2;
if(buf == buf2){
console.log('true');
}
else{
console.log('false');
}
}());
如果我尝试比较视图和view2它又是假的。
答案 0 :(得分:8)
您无法使用==
或===
直接在JavaScript中比较两个对象
这些运算符只会检查引用的相等性(即表达式是否引用同一个对象)。
但是,您可以使用DataView
或ArrayView
个对象来检索ArrayBuffer
个对象的特定部分的值并进行检查。
如果您想检查标题:
if ( view1.getUint8 (0) == view2.getUint8 (0)
&& view1.getUint16(2) == view2.getUint16(2)) ...
或者如果你想检查你的缓冲区的全局性:
function equal (buf1, buf2)
{
if (buf1.byteLength != buf2.byteLength) return false;
var dv1 = new Int8Array(buf1);
var dv2 = new Int8Array(buf2);
for (var i = 0 ; i != buf1.byteLength ; i++)
{
if (dv1[i] != dv2[i]) return false;
}
return true;
}
如果您想基于ArrayBuffer
实现复杂的数据结构,我建议您创建自己的类,否则您将不得不求助于繁琐的原始DataView
/ ArrayView
个实例你想要将火柴杆移入和移出结构的时间。
答案 1 :(得分:3)
在当今的V8中,DataView
现在应该“可用于对性能至关重要的实际应用程序” — https://v8.dev/blog/dataview
下面的函数根据您已实例化的对象测试是否相等。如果您已经有TypedArray
个对象,则可以直接比较它们而无需为其创建其他DataView
个对象(欢迎有人来衡量这两个选项的性能)。
// compare ArrayBuffers
function arrayBuffersAreEqual(a, b) {
return dataViewsAreEqual(new DataView(a), new DataView(b));
}
// compare DataViews
function dataViewsAreEqual(a, b) {
if (a.byteLength !== b.byteLength) return false;
for (let i=0; i < a.byteLength; i++) {
if (a.getUint8(i) !== b.getUint8(i)) return false;
}
return true;
}
// compare TypedArrays
function typedArraysAreEqual(a, b) {
if (a.byteLength !== b.byteLength) return false;
return a.every((val, i) => val === b[i]);
}
答案 2 :(得分:3)
要测试两个TypedArray之间的相等性,请考虑使用every方法,该方法会在发现不一致时退出:
const a = Uint8Array.from([0,1,2,3]);
const b = Uint8Array.from([0,1,2,3]);
const c = Uint8Array.from([0,1,2,3,4]);
const areEqual = (first, second) =>
first.length === second.length && first.every((value, index) => value === second[index]);
console.log(areEqual(a, b));
console.log(areEqual(a, c));
这比替代方法(例如toString()
比较)便宜,后者甚至在找到差异之后也可以迭代其余阵列。
答案 3 :(得分:1)
您始终可以将数组转换为字符串并进行比较。 E.g。
cd src; code index.js; cd public; cd ../..;
答案 4 :(得分:1)
在一般的javascript中,您当前必须比较两个ArrayBuffer对象,方法是用TypedArray包装每个对象,然后手动迭代每个元素并进行逐元素相等。
如果基础缓冲区是2字节或4字节内存对齐的,则可以通过使用Uint16或Uint32类型数组进行比较来进行重大优化。
/**
* compare two binary arrays for equality
* @param {(ArrayBuffer|ArrayBufferView)} a
* @param {(ArrayBuffer|ArrayBufferView)} b
*/
function equal(a, b) {
if (a instanceof ArrayBuffer) a = new Uint8Array(a, 0);
if (b instanceof ArrayBuffer) b = new Uint8Array(b, 0);
if (a.byteLength != b.byteLength) return false;
if (aligned32(a) && aligned32(b))
return equal32(a, b);
if (aligned16(a) && aligned16(b))
return equal16(a, b);
return equal8(a, b);
}
function equal8(a, b) {
const ua = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
const ub = new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
return compare(ua, ub);
}
function equal16(a, b) {
const ua = new Uint16Array(a.buffer, a.byteOffset, a.byteLength / 2);
const ub = new Uint16Array(b.buffer, b.byteOffset, b.byteLength / 2);
return compare(ua, ub);
}
function equal32(a, b) {
const ua = new Uint32Array(a.buffer, a.byteOffset, a.byteLength / 4);
const ub = new Uint32Array(b.buffer, b.byteOffset, b.byteLength / 4);
return compare(ua, ub);
}
function compare(a, b) {
for (let i = a.length; -1 < i; i -= 1) {
if ((a[i] !== b[i])) return false;
}
return true;
}
function aligned16(a) {
return (a.byteOffset % 2 === 0) && (a.byteLength % 2 === 0);
}
function aligned32(a) {
return (a.byteOffset % 4 === 0) && (a.byteLength % 4 === 0);
}
并通过
调用equal(buf1, buf2)
here are the performance tests用于1、2、4字节对齐的内存。
替代方法:
使用WASM还可以提高性能,但是将数据传输到堆的成本可能会抵消比较优势。
在Node.JS中,Buffer
可能会获得更高的性能,因为它将具有本机代码:Buffer.from(buf1, 0).equals(Buffer.from(buf2, 0))
答案 5 :(得分:0)
我编写了这些函数来比较最正常的数据类型。它适用于 ArrayBuffer、TypedArray、DataView、Node.js Buffer 和任何带有字节数据 (0-255) 的普通数组。
// It will not copy any underlying buffers, instead it will create a view into them.
function dataToUint8Array(data) {
let uint8array
if (data instanceof ArrayBuffer || Array.isArray(data)) {
uint8array = new Uint8Array(data)
} else if (data instanceof Buffer) { // Node.js Buffer
uint8array = new Uint8Array(data.buffer, data.byteOffset, data.length)
} else if (ArrayBuffer.isView(data)) { // DataView, TypedArray or Node.js Buffer
uint8array = new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
} else {
throw Error('Data is not an ArrayBuffer, TypedArray, DataView or a Node.js Buffer.')
}
return uint8array
}
function compareData(a, b) {
a = dataToUint8Array(a); b = dataToUint8Array(b)
if (a.byteLength != b.byteLength) return false
return a.every((val, i) => val == b[i])
}
答案 6 :(得分:-1)
就我而言,将ArrayBuffer转换为Blob是解决方案。但是,这可能不是通用的解决方案。
注意:我之前是从Blob创建的ArrayBuffer
new Blob([ArrayBuffer], { type: 'image/jpeg' })