《高性能javascript》读书笔记

96 阅读7分钟

写在前面:在同事推荐下通读了《高性能javascript》,还是略有收获,书中对使用js过程中比较散的优化规则进行了总结,茶余饭后读一读还是有点意思。这里简单记录下 js 的一些优化规则

1、 将script标签放到html的尾部

2、减少script标签的数量有助于改善速度

3、script标签中带有defer时

  • 可以放置在任意位置;对应的JavaScript 文件将在页面解析到<script>标签时开始下载,但并不会执行,直到DOM加载完成(onload事件被触发前)

4、使用动态脚本节点下载文件时,返回的代码通常会立刻执行

5、另一种无阻塞加载脚本的方法是使用XMLHttpRequest(XHR)对象获取脚本并注入页面中

6、一个标识符所在的位置越深,它的读写速度也就越慢。因此,函数中读写局部变量总是最快的,而读写全局变量通常是最慢的

7、一个好的经验法则是:如果某个跨作用域的值在函数中被引用一次以上,那么就把它存储到局部变量里。因为按照变量的寻址规则,会先局部,后全局。到全局时会最慢

8、无论是with语句还是try-catch语句的catch子句,以及包含eval()的函数,都被认为是动态作用域;

  • 动态作用域只存在于代码执行过程中,因此无法通过静态分析(查看代码结构)检测出来

9、在js中 in 操作符可以表示该对象是否有某个特定的属性

let a = {};
console.log(’toString’ in a)  //  true

10、什么是dom?

  • 文档对象模型(DOM)是一个语言无关的,用于操作XML和HTML文档的应用程序接口(API)

11、如何提升dom修改速度?

  • 减少访问DOM的次数,把运算尽量留在ECMAScript这一端处理

13、一般来说,对于任何类型的DOM访问,当同一个DOM属性或方法需要多次访问时,最好使用一个局部变量缓存此成员

14、选定dom元素时,

  • 可以使用 document.getElementById(), document.getElementsByTagName()也可以选择 document.querySelectorAll(‘p'), document.querySelectorAll(‘.classname’)

  • querySelectorAllgetxx 方法快很多

15、querySelectorAll 会返回一个NodeList ,其并不是一个数组,而是一个类数组对象

var errs=document.querySelectorAll('div.warning,div.notice');

16、querySelector()来获取第一个匹配的节点

17、offsetLeft、offsetTop、offsetWidth和offsetHeight

  • offsetTop和offsetLeft是指DOM元素的位置,也就是该元素的左上角相对于其最近的具有position属性(值不为static)的祖先元素的左上角的距离(假如祖先元素没有position为非static,则直接到body)。具体来说:

  • offsetTop表示元素的上边缘距其最近的具有定位(position)属性的祖先元素的上边缘的距离,以像素为单位。

  • offsetLeft表示元素的左边缘距其最近的具有定位(position)属性的祖先元素的左边缘的距离,以像素为单位。

  • 如果元素没有具有position属性的祖先元素,那么offsetTop和offsetLeft相对于文档(document)的左上角(body)计算。注意,offsetTop和offsetLeft不包含元素本身的border,元素本身的border会算到 offsetWidth 中,

  • 这两个属性通常在JavaScript中用于计算元素的位置,并且可以与offsetWidth和offsetHeight属性一起使用以计算元素的大小和位置。

  • offsetWidth是指DOM元素的外部宽度,包括元素的可见宽度和左右内边距(padding)的宽度、左右边框(border)的宽度,以及左右滚动条(scrollbar)的宽度(如果有的话)。因此,offsetWidth的值通常大于或等于clientWidth的值

18、clientTop,clientLeft,clientWidth,clientHeight

  • clientWidth和clientHeight是指DOM元素的大小,也就是该元素的内容(content)宽度和高度加上左右(或上下)内边距(padding)的宽度和高度。具体来说:

  • clientWidth表示元素的内容(content)宽度加上左右内边距(padding)的宽度,以像素为单位。

  • clientHeight表示元素的内容(content)高度加上上下内边距(padding)的高度,以像素为单位。

  • 注意,clientWidth和clientHeight不包括元素的边框(border)、外边距(margin)和滚动条(scrollbar)的大小。

  • 这两个属性通常在JavaScript中用于计算元素的大小和位置,并且可以与scrollWidth和scrollHeight属性一起使用以计算元素的滚动区域的大小和位置

  • clientWidth是指DOM元素的内部宽度,包括元素的内容(content)宽度和左右内边距(padding)的宽度,但不包括左右边框(border)和滚动条(scrollbar)的宽度。因此,clientWidth的值通常小于或等于offsetWidth的值

  • 因此,offsetWidth的值通常大于或等于clientWidth的值。

  • clientTop,clientLeft其宽度就是元素border的宽度,一般不怎么用

19、scrollTop、scrollLeft、scrollWidth和scrollHeight是指DOM元素的滚动区域的位置和尺寸。

  • scrollTop表示元素在垂直方向滚动的距离,以像素为单位。

  • scrollLeft表示元素在水平方向滚动的距离,以像素为单位。

  • scrollWidth表示元素的滚动区域的宽度,包括被隐藏的部分,以像素为单位。

  • scrollHeight表示元素的滚动区域的高度,包括被隐藏的部分,以像素为单位。

  • 这些属性通常在JavaScript中用于处理滚动事件,以及计算元素的滚动区域的大小和位置。可以通过设置这些属性的值,来实现元素的滚动。如果元素的滚动区域没有被隐藏,那么scrollWidth和scrollHeight的值将等于元素的clientWidth和clientHeight

20、getComputedStyle的作用是什么

  • getComputedStyle()是JavaScript中的一个方法,用于获取指定元素的最终计算样式(computed style),即应用在元素上的所有样式的值,包括元素本身的样式、父级元素的样式、以及浏览器的默认样式

21、如何实现样式的追加,而不是覆盖

    el.style.cssText+='; border-left: 1px;';

22、如何实现对节点备份

5092EFD8-0AF1-4D2A-90F8-CCEE1BF48EEC.png

使用 dom.cloneNode

23、for-in循环比其他的循环速度要更慢,因为要每次迭代需要搜索实例或者原型属性

  • 速度相当于是普通for循环的 1/7

24、在循环中比较节约时间的情况

5092EFD8-0AF1-4D2A-90F8-CCEE1BF48EEC.png

  • 将对象items.length的值存在局部变量中

25、在条件过多时,为什么switch比if-else要更好?

  • 当判断条件很多时,if-else语句需要逐个判断每个条件,直到找到匹配的条件,这会导致性能下降。而switch语句使用了一种跳转表的方式,可以直接跳转到匹配的条件,因此执行效率更高

26、改善循环性能的最佳方式是减少每次迭代的运算量和减少循环迭代次数

27、对于使用迭代时容易导致栈溢出,一般会考虑将算过的数据缓存下来,避免重复运算

28、连接字符串的优化

  • 使用str+="one"+"two"  效率要更好

29、concat不仅可以拼接数组,也可以拼接字符串

    var a = ‘xx’
    a.concat('ddd’)

30、浏览器中的ui线程和js引擎线程是互斥的: 这意味着当JavaScript代码正在执行时用户界面无法响应输入,反之亦然。当JavaScript代码执行时,用户界面处于“锁定”状态

31、对于耗时比较长的js逻辑,一般可以使用webwork来执行

32、对于图片文件在客户端和服务端的传递,可以将多个图片转成base64然后拼接,然后在客户端进行解码

37、xml和json都是用于数据交换的格式,其两者语法有比较大的区别

38、AJAX 和 XMLHttpRequest 的关系是什么

  • AJAX 是基于 XMLHttpRequest 对象实现的。

39、能直接执行字符串的有以下几种方式:

3093EA1F-8921-47F1-AA73-6300B995A827.png

  • 每次调用eval()时都要创建一个新的解释器/编译器实例。同样的过程也发生在使用Function()、setTimeout()和setInterval()时,这必然使得代码执行的速度变慢

40、对代码中的重复工作,有以下几种优化方案: 延迟加载;条件预加载

  • 延迟加载: 通过覆写函数,只会在第一次检测是否有对应的方法,后续覆写后就不需要在执行多余逻辑

F75E1A9B-ED80-4000-ADCF-6F2A4913B135.png

  • 条件预加载:核心是在脚本加载期间提前检测,而不是等到函数被调用时

3415DE9E-FCF6-48AA-9132-EA1D9319F034.png