到底怎么写更快?js几种常规同类写法的效率比较

133 阅读4分钟

【阅读时间 1min】在编写js代码的时候,我们时常会面临是用自己习惯的写法,还是用新的特性的抉择之中,所以这次我们就对比了几种写法在不同环境下的各种性能表现,试图想要找出各个写法之间的效率差距以及适用场景,实验仅供参考。

Preset

Container: MacBook Pro (13-inch, 2019, Four Thunderbolt 3 ports) 2.4 GHz 四核Intel Core i5 16 GB 2133 MHz LPDDR3

node v12: Node.js 12.9.0 on Darwin 64-bit

node v14: Node.js 14.19.0 on Darwin 64-bit

node v16: Node.js 16.14.0 on Darwin 64-bit

chrome: Chrome 99.0.4844.51 on OS X 10.15.7 64-bit

KV存储是object还是Map

map-read-write.js

我们分别对于map与object的创建,插入,删除进行了对比

项目\ops/snode v12node v14node v16chrome
Map create29,267,058.9426,608,897.7937,062,367.7043,231,219.37
Object create857,444,575.77888,349,667.55854,106,336.82883,308,254.81
Map write877,461.76968,992.94987,354.91817,214.31
Object write920,314.75794,521.57769,993.95819,094.59
Map read1,145,098.401,216,883.641,218,311.64915,547.89
Object read1,517,999.411,509,986.541,386,267.981,107,861.03
Map has1,219,815.391,346,438.131,308,262.64978,764.82
Object has929,497.42870,248.41980,060.13778,028.76
Map delete1,870,226.721,742,328.901,926,306.471,139,510.35
Object delete1,331,723.111,320,285.411,185,889.90987,752.52

可以看出,Object在创建,读写方面都是比Map拥有较好的性能的,但是在判断是否有key,还有销毁map的时候,Map有微弱的性能优势,所以单池大批量读和删的场景Map会占一些优势,但因为Object有着天生的优化,在创建大量KV池的时候,优先选择object。

判断包含到底用哪个 Set/Map/Array

has.js

我们分别对是否含有某个key来进行实验,只对has/includes进行对比

项目\ops/snode v12node v14node v16chrome
Array Has52,806,651.4749,281,258.7047,900,764.3249,808,869.46
Set Has2,911,871.482,359,545.002,411,060.822,419,522.60
Map Has51,391,811.1748,684,779.9949,292,788.3650,297,773.89

\

这个测试可能会让大家对Set这个新特性又更新的认知,对的,他的实现在V8的各个运行时里面看起来都是鲜有优化的,而Array的inculdes和Map的has差别不大,大家可以根据自己的原生数据类型选择,原来的数据构造成什么,就是使用什么来进行判断。

遍历实例怎样更快 loop/foreach/for of

iterator.js

对比不同方法遍历一个500元素的数组那个更快

项目\ops/snode v12node v14node v16chrome
Loop for27,446.6025,999.7624,735.3929,790.86
Loop while26,895.4326,168.2824,949.5129,101.64
forEach25,506.3125,683.9325,699.7029,558.08
for of27,649.3026,814.1126,550.9723,540.74

虽然就连我自己也觉得这个项目没有什么意义,但是从实际上来看,所有的遍历方法都是差不多效率的,但是值得注意的是,for of写法在node js里面一直有不错的性能,反而在chrome中会表现的比较逊色,普遍来说,我们可以放心的使用各种方法,但是对于大数据量/array意外遍历的情况下,多使用 for of也许是个不错的选择。

递归与循环差距有多大

recursion.js

我们通过对比递归和循环,来试图找到他们之间的效率差距,本次只会对比node v16和chrome

项目\ops/s2101001000500010000
Loop182,893,271.35139,493,808.9510,814,243.64899,043.46144,020.4781,408.54
recursion30,309,523.457,700,480.80811,277.3475,769.8414,792.83\
Loop chrome171,274,493.69135,085,494.6210,762,253.55907,379.43181,799.7990,392.25
recursion chrome41,101,543.757,752,724.51746,479.7573,450.7913,642.506,359.99

可以明显的看出,随着递归层数的增多,性能下降十分明显,而且对于普遍不高的node运行内存,递归在1w层左右就已经爆栈,而且只要层数在10层以上,两者的效率差距已经达到了10-14倍的差距,所以尽管有尾递归优化一说,但是如果要获得不错的性能,还是得好好进行循环的优化。