我正在制作一个具有特定大小的字符串环形缓冲区。我为此目的使用一个数组,只需推送和取消。单个索引是单个字符。我不想使用字符串,因为每次我将字符推入缓冲区时都会发生复制。现在我需要在这个缓冲区上使用正则表达式。问题在于,现在每次我想要匹配时我需要array.join()
这样做是相当昂贵的......
现在我想知道是否可以直接在字符数组上使用正则表达式而不是先将其转换为字符串。
我想如果有一个可变的字符串类型我永远不会有这个问题...
答案 0 :(得分:1)
同意..! JS字符串是不可变的,但是你对连接的关注是耗时的并不合理。我可以确认在Chrome,Firefox,Opera,IE11和Safari中对1,000,000个随机字符阵列进行Array.prototype.join()
操作大约需要10~40ms,具体取决于引擎。是的......就是这样。 (特别是蜘蛛猴闪耀)让我们看看
var arr = [],
match = [],
longStr = "",
count = 1000000,
start = 0,
end = 0;
for (var i=0; i<count; i++){
arr.push((+new Date()*Math.random()).toString(36)[0]);
}
start = performance.now();
longStr = arr.join("");
end = performance.now();
console.log("Concatenation took "+(end-start)+" msecs");
// Concatenation took 10.875 msecs.. Wow Firefox..!
start = performance.now();
match = longStr.match(/7{5,}/g);
!match && (match = [])
end = performance.now();
console.log("Regex match took "+(end-start)+" msecs and found " +match.length+" matches as: ", match);
//Regex match took 6.550000000046566 msecs and found 1 matches as: ["77777"]
所以在完成这些测试之后,我决定尝试回答你的问题。我们需要发明我们自己的可变字符串对象。实际上创建它非常简单。具有特殊功能的异常数组对象,也可以访问Array.prototype
个函数。就像字符串对象一样,它将有一个名为primitiveValue
的额外属性,每次更新length属性时,我们将执行this.primitiveValue = this.join();
操作,以便所有Array.prototype
函数访问{{1} }属性将自动更新length
。如果我们有一个写入繁重的工作流程,这将降低性能。好消息是我们可以完全控制我们如何更新primitiveValue
。如果我们喜欢,我们可以在每次对length属性的写访问时跳过更新它,并且可以在将regex应用于字符串内容之前手动执行。或者我们甚至可以将{regex函数添加到primitiveValue
和猴子补丁中,将RingBuffer.prototype
作业连接到它们。这里有很多可能性。
primitiveValue
所以我用{100,000}随机字符填充function RingBuffer(){
this.primitiveValue = "";
this.__len;
Object.defineProperty(this, "length", {
enumerable: true,
configurable: true,
get: this.getLength,
set: this.setLength
});
}
RingBuffer.prototype = Array.prototype;
RingBuffer.prototype.constructor = RingBuffer;
RingBuffer.prototype.getLength = function(){
return this.__len;
};
RingBuffer.prototype.setLength = function(val){
this.__len = val;
this.primitiveValue = this.join("");
};
var ringu = new RingBuffer();
。 Chrome 49的基准测试是这样的;
ringu
因此,根据您进行写入的频率或在应用正则表达式之前需要连接var longStr = "",
count = 100000,
start = performance.now(),
end = 0;
for (var i=1; i<=count; i++){
ringu.push((+new Date()*Math.random()).toString(36)[0]);
if (!(i % 10000)){
end = performance.now();
console.log(i/10000+". 10000 pushes done at :"+(end - start)+" msecs");
start = end;
}
}
console.log("ringu is filled with " + count + " random characters");
start = performance.now();
longStr = ringu.join("");
end = performance.now();
console.log("Last concatenation took "+(end-start)+" msecs");
1. 10000 pushes done at :1680.6399999996647 msecs
2. 10000 pushes done at :4873.2599999997765 msecs
3. 10000 pushes done at :8044.155000000261 msecs
4. 10000 pushes done at :11585.525000000373 msecs
5. 10000 pushes done at :14642.490000000224 msecs
6. 10000 pushes done at :17998.389999999665 msecs
7. 10000 pushes done at :20814.979999999516 msecs
8. 10000 pushes done at :24024.445000000298 msecs
9. 10000 pushes done at :27146.375 msecs
10. 10000 pushes done at :30347.794999999925 msecs
ringu is filled with 100000 random characters
Last concatenation took 3.510000000707805 msecs
的频率,您可以决定在何处调用primitiveValue
指令。 500K项目RingBuffer的平均连接时间将小于30ms。
嗯......这就是SpiderMonkey的结果。因此,如果您要在Node.Js上运行类似的代码,那么尝试使用Spider Monkey或ChakraCore引擎而不是使用V8的Node配置JXCore可能会更明智。
this.join("");