写点什么

高性能 JavaScriptの七 -- 编程实践小技巧

用户头像
空城机
关注
发布于: 2021 年 06 月 08 日
高性能 JavaScriptの七 -- 编程实践小技巧

目录:编程实践

避免双重求值(Double Evaluation)

使用 Object/Array 直接量

避免重复工作

小节


随着 web 开发者对 JavaScript 和浏览器的推动,在 JavaScript 中出现了一些十分特别的模式,有精华也有糟粕(对 js 性能上来说的),毕竟 JavaScript 可以是前端最重要的组成之一,“人红是非多”。


这些模式的出现是由于 Web 中 JavaScript 的特性决定的,前端你没得选,后端还可以换语言



避免双重求值(Double Evaluation)

JavaScript 与很多其他语言一样,允许你在程序中提取一个包含代码的字符串,然后动态执行


四种实现的标准方法:


  • Function() 构造函数

  • eval()

  • setTimeout()

  • setInterval()


例子:

var num1 = 1,num2 = 6;//eval()执行代码字符串sum = eval("num1 + num2");//Function()构造函数执行代码字符串sum = new Function("num1", "num2", "return num1 +num2");//setTimeout()执行代码字符串setTimeout("sum = num1 +num2", 100);//setInterval()执行代码字符串setInterval("sum = num1 +num2", 100)
复制代码


当在 JavaScript 代码中执行另一段 JavaScript 代码时,都会导致双重求值的性能消耗


上面这些代码首先会以正常方式求值,然后在执行过程中对包含于字符串中的代码发起另一个求值运算


双重求值和直接求值性能对比:如果觉得测试代码不对的朋友,可以在评论区留言告诉我,不断修正

var num1 = 1,num2 = 6;console.time('双重求值')for (var i = 0; i < 10000; i++) {   //eval()执行代码字符串    sum = eval("num1 + num2");}console.log(sum)console.timeEnd('双重求值')console.time('直接求值')for (var i = 0; i < 10000; i++) {   sum = num1 + num2;}console.log(sum)console.timeEnd('直接求值')
复制代码


chrome 浏览器:


IE 浏览器:


火狐浏览器:


从上面的测试可以看出,双重求值的速度远远不如直接求值


原因:每次调用 eval()都要创建一个新的解释器/编译器实例,另外三个也是一样,所以这必然会导致代码执行速度变慢


setTimeoutsetInterval两个延时函数,第一个参数最好传入函数而不是字符串。当然了,正经人谁在延时函数上不写函数写字符串代码呀! 狗头.jpg


避免双重求值能大大提高 JavaScript 运行期的性能效率


使用 Object/Array 直接量

在 JavaScript 中创建对象和数组的方法有很多种,但是使用对象和数组直接量是最快的方式



直接量赋值和 new Object 赋值对比:

console.time('对象直接量')for (var i = 0; i < 10000; i++) {    var obj = {        name:'空城机',        age: 25,        sex: '男'    }}console.timeEnd('对象直接量')
console.time('new Object方式')for (var i = 0; i < 10000; i++) { var obj = new Object(); obj.name = '空城机'; obj.age = 25; obj.sex = '男';}console.timeEnd('new Object方式')
复制代码


chrome 浏览器:


火狐浏览器:


因为在 22 年 IE 浏览器即将退出历史舞台,微软一些系统不会支持 IE11 了,所以这里就不提供 IE 的测试结果了

虽然也是一样的,大家可以自己尝试下



数组直接量和 new Array 对比

如果觉得测试代码不对的朋友,可以在评论区留言告诉我,不断修正

<script>    console.time('数组直接量')    for (var i = 0; i < 10000; i++) {        var arr = [30, '1', null]    }    console.timeEnd('数组直接量')    console.time('new Array方式')    for (var i = 0; i < 10000; i++) {       var arr = new Array();       arr[0] = 30,       arr[1] = '1',       arr[2] = null    }    console.timeEnd('new Array方式') </script>
复制代码


chrome 浏览器:


下面这里划重点了,在火狐浏览器测试结果很令我惊讶:


火狐浏览器:


火狐浏览器测试出来数组直接量的时间反倒更长,这河里吗?


然后我赶紧测试了下 IE 浏览器


IE 也符合之前的结论,那是什么原因导致火狐浏览器结果不同?


我又直接在火狐浏览器控制条输入代码,发现结果正确



所以我有两个猜测:1. 测试的数据量不够大 2. 火狐引擎的调整


接下来我调整了循环次数,但是火狐浏览器控制台结果两种性能差别不大,多次测试还是数组直接量的方式要慢一些


然后我调换了测试方法的位置,让 new Array 在上面先执行新的测试代码:

<script>    console.time('new Array方式')    for (var i = 0; i < 10000; i++) {       var arr = new Array();       arr[0] = 30,       arr[1] = '1',       arr[2] = null    }    console.timeEnd('new Array方式')    console.time('数组直接量')    for (var i = 0; i < 10000; i++) {        var arr = [30, '1', null]    }    console.timeEnd('数组直接量')</script>
复制代码

火狐:


这样结果就很明显了,数组直接量性能更快

好家伙,我直接 ?号就出来了


这是火狐引擎运行 js 的“小彩蛋”吗,上网找了半天资料也没找到,可能就是引擎加载的时候的差异吧


之后测试就直接在控制台输入测试了





避免重复工作

性能优化说的最多的就是避免重复工作


方式:

  • 延迟加载

  • 在方法被第一次调用时,检查决定使用那种方法去绑定事件处理起,然后原始函数被新函数覆盖

  • 延时函数第一次调用会消耗时间较长

  • 当一个函数在页面中不会立刻调用,可以使用延迟加载优化性能

  • 条件预加载

  • 在脚本加载前检测,适用于一个函数马上要被用到,并且在整个页面的生命周期中频繁出现的场合

  • 位操作

  • 在 JavaScript 中也有与或等操作,这些操作可以加快 js 的运算性能

  • 原生方法

  • 无论你的 JavaScript 代码如何优化,都不会比 JavaScript 引擎提供的原生方法更快

  • JavaScript 原生方法依旧提取存在浏览器中了,被编译成了机器码

  • 比如 Math 方法,进行复杂数学运算时,可以使用内置的 Math 对象中的方法

  • 菜鸟教程:JavaScript Math 对象


小节

平时写代码时可以优化的点①:避免使用双重求值的方法,比如 eval 和 Function 构造器,如果必须要用也没什么办法了。延迟函数记得写方法而不是代码字符串作为第一个参数。


平时写代码时可以优化的点②:对象直接量和数组直接量的性能优于于 new 出来的 Object 和 Array (虽然数组直接量在火狐浏览器有点奇怪)


平时写代码时可以优化的点③:去看上面如何避免重复工作


建议把这些知识的应用变成习惯



发布于: 2021 年 06 月 08 日阅读数: 23
用户头像

空城机

关注

曾经沧海难为水,只是当时已惘然 2021.03.22 加入

业余作者,在线水文 主要干前端的活,业余会学学python 欢迎各位关注,互相学习,互相进步

评论

发布
暂无评论
高性能 JavaScriptの七 -- 编程实践小技巧