【阅读时间 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/s | node v12 | node v14 | node v16 | chrome |
---|---|---|---|---|
Map create | 29,267,058.94 | 26,608,897.79 | 37,062,367.70 | 43,231,219.37 |
Object create | 857,444,575.77 | 888,349,667.55 | 854,106,336.82 | 883,308,254.81 |
Map write | 877,461.76 | 968,992.94 | 987,354.91 | 817,214.31 |
Object write | 920,314.75 | 794,521.57 | 769,993.95 | 819,094.59 |
Map read | 1,145,098.40 | 1,216,883.64 | 1,218,311.64 | 915,547.89 |
Object read | 1,517,999.41 | 1,509,986.54 | 1,386,267.98 | 1,107,861.03 |
Map has | 1,219,815.39 | 1,346,438.13 | 1,308,262.64 | 978,764.82 |
Object has | 929,497.42 | 870,248.41 | 980,060.13 | 778,028.76 |
Map delete | 1,870,226.72 | 1,742,328.90 | 1,926,306.47 | 1,139,510.35 |
Object delete | 1,331,723.11 | 1,320,285.41 | 1,185,889.90 | 987,752.52 |
可以看出,Object在创建,读写方面都是比Map拥有较好的性能的,但是在判断是否有key,还有销毁map的时候,Map有微弱的性能优势,所以单池大批量读和删的场景Map会占一些优势,但因为Object有着天生的优化,在创建大量KV池的时候,优先选择object。
判断包含到底用哪个 Set/Map/Array
has.js
我们分别对是否含有某个key来进行实验,只对has/includes进行对比
项目\ops/s | node v12 | node v14 | node v16 | chrome |
---|---|---|---|---|
Array Has | 52,806,651.47 | 49,281,258.70 | 47,900,764.32 | 49,808,869.46 |
Set Has | 2,911,871.48 | 2,359,545.00 | 2,411,060.82 | 2,419,522.60 |
Map Has | 51,391,811.17 | 48,684,779.99 | 49,292,788.36 | 50,297,773.89 |
\
这个测试可能会让大家对Set这个新特性又更新的认知,对的,他的实现在V8的各个运行时里面看起来都是鲜有优化的,而Array的inculdes和Map的has差别不大,大家可以根据自己的原生数据类型选择,原来的数据构造成什么,就是使用什么来进行判断。
遍历实例怎样更快 loop/foreach/for of
iterator.js
对比不同方法遍历一个500元素的数组那个更快
项目\ops/s | node v12 | node v14 | node v16 | chrome |
---|---|---|---|---|
Loop for | 27,446.60 | 25,999.76 | 24,735.39 | 29,790.86 |
Loop while | 26,895.43 | 26,168.28 | 24,949.51 | 29,101.64 |
forEach | 25,506.31 | 25,683.93 | 25,699.70 | 29,558.08 |
for of | 27,649.30 | 26,814.11 | 26,550.97 | 23,540.74 |
虽然就连我自己也觉得这个项目没有什么意义,但是从实际上来看,所有的遍历方法都是差不多效率的,但是值得注意的是,for of写法在node js里面一直有不错的性能,反而在chrome中会表现的比较逊色,普遍来说,我们可以放心的使用各种方法,但是对于大数据量/array意外遍历的情况下,多使用 for of也许是个不错的选择。
递归与循环差距有多大
recursion.js
我们通过对比递归和循环,来试图找到他们之间的效率差距,本次只会对比node v16和chrome
项目\ops/s | 2 | 10 | 100 | 1000 | 5000 | 10000 |
---|---|---|---|---|---|---|
Loop | 182,893,271.35 | 139,493,808.95 | 10,814,243.64 | 899,043.46 | 144,020.47 | 81,408.54 |
recursion | 30,309,523.45 | 7,700,480.80 | 811,277.34 | 75,769.84 | 14,792.83 | \ |
Loop chrome | 171,274,493.69 | 135,085,494.62 | 10,762,253.55 | 907,379.43 | 181,799.79 | 90,392.25 |
recursion chrome | 41,101,543.75 | 7,752,724.51 | 746,479.75 | 73,450.79 | 13,642.50 | 6,359.99 |
可以明显的看出,随着递归层数的增多,性能下降十分明显,而且对于普遍不高的node运行内存,递归在1w层左右就已经爆栈,而且只要层数在10层以上,两者的效率差距已经达到了10-14倍的差距,所以尽管有尾递归优化一说,但是如果要获得不错的性能,还是得好好进行循环的优化。