使用Javascript在localStorage中存储大型整数数组的最有效方法
*这里的“高效”基本上是指更小的大小(减少IO等待时间)和更快的检索/反序列化时间。储存时间并不重要 我必须在浏览器的本地存储中存储几十个整数数组,每个数组有1800个0-50范围内的值——也就是说,作为字符串 显然,最简单的方法是只使用Javascript在localStorage中存储大型整数数组的最有效方法,javascript,html,local-storage,web-storage,Javascript,Html,Local Storage,Web Storage,*这里的“高效”基本上是指更小的大小(减少IO等待时间)和更快的检索/反序列化时间。储存时间并不重要 我必须在浏览器的本地存储中存储几十个整数数组,每个数组有1800个0-50范围内的值——也就是说,作为字符串 显然,最简单的方法是只JSON.stringifyit,但是,考虑到数据的范围是众所周知的,这会添加很多不必要的信息。其中一个阵列的平均大小约为5500字节 以下是我尝试过的一些其他方法(结果大小,以及最后反序列化1000次的时间) 零填充数字,使每个数字都有2个字符长,例如: [5,
JSON.stringify
it,但是,考虑到数据的范围是众所周知的,这会添加很多不必要的信息。其中一个阵列的平均大小约为5500字节
以下是我尝试过的一些其他方法(结果大小,以及最后反序列化1000次的时间)
- 零填充数字,使每个数字都有2个字符长,例如:
[5, 27, 7, 38] ==> "05270738"
- 以50为基数对其进行编码:
[5, 11, 7, 38] ==> "5b7C"
- 仅将该值用作字符代码(添加32以避免开始时出现奇怪的控制字符):
size Chrome 18 Firefox 11
-------------------------------------------------
JSON.stringify 5286 60ms 99ms
zero-padded 3600 354ms 703ms
base 50 1800 315ms 400ms
charCodes 1800 21ms 178ms
我的问题是,是否有更好的方法我还没有考虑
更新MΓΓББLL建议对数据进行压缩。使用基数50和字符码数据。我还测试了aroth的代码(将4个整数打包成3个字节)。我得到了这些结果:
size Chrome 18 Firefox 11
-------------------------------------------------
LZW base 50 1103 494ms 999ms
LZW charCodes 1103 194ms 882ms
bitpacking 1350 2395ms 331ms
假设(在您的测试中)压缩所花费的时间比减少大小所节省的时间要多,您的字符编码是在不进行位移位的情况下得到的最小编码。当前每个数字使用一个字节,但如果保证它们足够小,则可以在每个字节中放入两个数字。这可能是一个过度优化,除非这是一个非常热门的代码。 你可能想考虑使用<代码> UTI8LARDAs/CODE >或<代码> ArrayBuffer < /代码>。展示了它是如何完成的。复制他的逻辑,这里是一个示例,假设您有一个名为
arr
的现有Uint8Array
function arrayBufferToBinaryString(buffer, cb) {
var blobBuilder = new BlobBuilder();
blobBuilder.append(buffer);
var blob = blobBuilder.getBlob();
var reader = new FileReader();
reader.onload = function (e) {
cb(reader.result);
};
reader.readAsBinaryString(blob);
}
arrayBufferToBinaryString(arr.buffer, function(s) {
// do something with s
});
如果范围为0-50,则可以将4个数字打包为3个字节(每个数字6位)。这将允许您使用~1350字节存储1800个数字。此代码应执行以下操作:
window._firstChar = 48;
window.decodeArray = function(encodedText) {
var result = [];
var temp = [];
for (var index = 0; index < encodedText.length; index += 3) {
//skipping bounds checking because the encoded text is assumed to be valid
var firstChar = encodedText.charAt(index).charCodeAt() - _firstChar;
var secondChar = encodedText.charAt(index + 1).charCodeAt() - _firstChar;
var thirdChar = encodedText.charAt(index + 2).charCodeAt() - _firstChar;
temp.push((firstChar >> 2) & 0x3F); //6 bits, 'a'
temp.push(((firstChar & 0x03) << 4) | ((secondChar >> 4) & 0xF)); //2 bits + 4 bits, 'b'
temp.push(((secondChar & 0x0F) << 2) | ((thirdChar >> 6) & 0x3)); //4 bits + 2 bits, 'c'
temp.push(thirdChar & 0x3F); //6 bits, 'd'
}
//filter out 'padding' numbers, if present; this is an extremely inefficient way to do it
for (var index = 0; index < temp.length; index++) {
if(temp[index] != 63) {
result.push(temp[index]);
}
}
return result;
};
window.encodeArray = function(array) {
var encodedData = [];
for (var index = 0; index < dataSet.length; index += 4) {
var num1 = dataSet[index];
var num2 = index + 1 < dataSet.length ? dataSet[index + 1] : 63;
var num3 = index + 2 < dataSet.length ? dataSet[index + 2] : 63;
var num4 = index + 3 < dataSet.length ? dataSet[index + 3] : 63;
encodeSet(num1, num2, num3, num4, encodedData);
}
return encodedData;
};
window.encodeSet = function(a, b, c, d, outArray) {
//we can encode 4 numbers in 3 bytes
var firstChar = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); //6 bits for 'a', 2 from 'b'
var secondChar = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); //remaining 4 bits from 'b', 4 from 'c'
var thirdChar = ((c & 0x03) << 6) | (d & 0x3F); //remaining 2 bits from 'c', 6 bits for 'd'
//add _firstChar so that all values map to a printable character
outArray.push(String.fromCharCode(firstChar + _firstChar));
outArray.push(String.fromCharCode(secondChar + _firstChar));
outArray.push(String.fromCharCode(thirdChar + _firstChar));
};
窗口。_firstChar=48;
window.decodeArray=函数(encodedText){
var结果=[];
var-temp=[];
对于(变量索引=0;索引>2)&0x3F);//6位,“a”
临时推送(((firstChar&0x03)>4)和0xF));//2位+4位,“b”
临时推送((secondChar&0x0F)>6)&0x3));//4位+2位,“c”
临时推送(thirdChar&0x3F);//6位'd'
}
//过滤掉“填充”数字(如果存在);这是一种效率极低的方法
对于(var索引=0;索引4)&0x03);//6位表示“a”,2位表示“b”
var secondChar=((b&0x0F)>2)&0x0F);//来自“b”的剩余4位,来自“c”的剩余4位
变量thirdChar=((c&0x03)尝试将base 50或charCodes方法与deflate/gzip相结合。我不确定是否有足够的数据用于压缩,以满足开销的需要,但检查一下也无妨。@mö最多两个字节(每个字节)在计算数据大小时,一定要考虑到这一点。0-50之间的数字占6位。你最好希望每个字节有1.33个数字。不过,正如前面所述,你可以很容易地将两个数字打包到一个UTF-16代码点中。我昨晚睡觉后也有同样的想法,但谢天谢地,你帮我省去了实际使用时的头疼计算实现。我已经在OP中的表格中添加了基准测试结果。不幸的是,Javascript的位操作似乎没有得到很好的优化。而且,顺序很重要,所以Bucket的想法是不可行的。更新:Chrome的位操作没有得到优化。Firefox似乎做得很好(至少是比较而言)。有两件事:首先,在U+0100
之前,您不会在一行中获得256个可打印字符。从U+0080
到U+00ff
的范围是控制字符。因此,偏移48不会在编码字符串中只提供可打印字符。请看-警报显示“12字节”,但我只计算11个字符。其次,JavaScript字符串存储为16位整数的数组。您必须将8个数字打包为6个字节(3个字符)。除非您仅使用一半的位,否则您将无法使用可打印字符构造编码字符串。
window._firstChar = 48;
window.decodeArray = function(encodedText) {
var result = [];
var temp = [];
for (var index = 0; index < encodedText.length; index += 3) {
//skipping bounds checking because the encoded text is assumed to be valid
var firstChar = encodedText.charAt(index).charCodeAt() - _firstChar;
var secondChar = encodedText.charAt(index + 1).charCodeAt() - _firstChar;
var thirdChar = encodedText.charAt(index + 2).charCodeAt() - _firstChar;
temp.push((firstChar >> 2) & 0x3F); //6 bits, 'a'
temp.push(((firstChar & 0x03) << 4) | ((secondChar >> 4) & 0xF)); //2 bits + 4 bits, 'b'
temp.push(((secondChar & 0x0F) << 2) | ((thirdChar >> 6) & 0x3)); //4 bits + 2 bits, 'c'
temp.push(thirdChar & 0x3F); //6 bits, 'd'
}
//filter out 'padding' numbers, if present; this is an extremely inefficient way to do it
for (var index = 0; index < temp.length; index++) {
if(temp[index] != 63) {
result.push(temp[index]);
}
}
return result;
};
window.encodeArray = function(array) {
var encodedData = [];
for (var index = 0; index < dataSet.length; index += 4) {
var num1 = dataSet[index];
var num2 = index + 1 < dataSet.length ? dataSet[index + 1] : 63;
var num3 = index + 2 < dataSet.length ? dataSet[index + 2] : 63;
var num4 = index + 3 < dataSet.length ? dataSet[index + 3] : 63;
encodeSet(num1, num2, num3, num4, encodedData);
}
return encodedData;
};
window.encodeSet = function(a, b, c, d, outArray) {
//we can encode 4 numbers in 3 bytes
var firstChar = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); //6 bits for 'a', 2 from 'b'
var secondChar = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); //remaining 4 bits from 'b', 4 from 'c'
var thirdChar = ((c & 0x03) << 6) | (d & 0x3F); //remaining 2 bits from 'c', 6 bits for 'd'
//add _firstChar so that all values map to a printable character
outArray.push(String.fromCharCode(firstChar + _firstChar));
outArray.push(String.fromCharCode(secondChar + _firstChar));
outArray.push(String.fromCharCode(thirdChar + _firstChar));
};