美文网首页
JS性能优化——JavaScript语言的优化

JS性能优化——JavaScript语言的优化

作者: yapingXu | 来源:发表于2020-11-11 22:54 被阅读0次

拉勾大前端的学习笔记,仅作为学习记录

内容概要

  • 内存管理
  • 垃圾回收与常见GC算法
  • V8引擎的垃圾回收
  • Performance工具
  • 代码优化实例

内存管理

  • 内存: 由可读写的单元组成,表示一片可操作的空间
  • 管理:人为的去操作一片空间的申请,使用和释放
  • 内存管理:开发者主动申请空间、使用空间、释放空间
  • 管理流程:申请-使用-释放

Js中的内存管理

  • 申请内存空间
// 申请
let obj = {}
// 使用
obj.name="lg"
// 释放
obj = null

Js中的垃圾回收

什么样的内容会被当做垃圾
因为js中内存管理是自动的,所以当对象不再被引用,对象不能从根上访问到,都是垃圾

可达对象
可以通过引用、作用于链访问到的对象就是可达对象
可达的标准是从根出发是否能够被找到
js中根就可以理解为是全局变量对象

垃圾回收
找到垃圾,让js的执行引擎来进行空间的释放和回收

js中的引用和可达

待补充

GC回收机制

GC的定义和作用

  • GC就是垃圾回收机制的简写
  • GC可以找到内存中的垃圾、并释放和回收空间

GC里面的垃圾是什么

  • 程序中不再需要使用的对象
function func(){
  name = 'lg'
  console.log(`${name} is a coder`)
}
func()
  • 程序中不能再访问到的对象
function func(){
  const name = 'lg'
  console.log(`${name} is a coder`)
}
func()

GC算法是什么

  • GC是一种机制,垃圾回收器完成具体工作
  • 工作的内容就是查找垃圾,释放空间,回收空间
    • 如何查找空间 ?
    • 释放空间的时候应该怎样去释放 ?
    • 回收空间的时候要怎样进行去分配 ?
  • 算法就是工作时查找和回收所遵循的规则

常见的GC算法

  • 引用计数 : 通过一个数字判断当前对象是不是一个垃圾
  • 标记清除: 在GC工作时给活动对象加标记判断对象是否是垃圾
  • 标记整理:和标记清除类似,只不过在后续回收过程会做一些事情
  • 分代回收:在V8中会用到的回收机制
引用计数算法实现原理

核心思想:设置引用数,判断当前引用数是否为0
算法规则:当某个对象引用关系发生改变的时候,引用计数器会去修改这个对象所对应的引用数值,引用数字为0时立即回收
优点

  • 发现垃圾立即回收
  • 最大限度减少程序暂停

缺点

  • 无法回收循环引用的对象
function func(){
  const obj1 = {}
  const obj2 = {}

  obj1.name = obj2
  obj2.name = obj1  // 当垃圾回收obj1的时候会发现obj1被obj2所引用,obj1的引用计数不为0,所以GC引用计数算法下,obj1不能被回收
}
func()
  • 时间开销大
标记清除算法的实现原理

核心思想:分标记和清除两个阶段

  • 标记阶段: 遍历所有对象找到并标记活动对象(也就是可达对象)
  • 清除阶段:遍历所有对象清除没有被标记的对象,把第一阶段的标记抹掉方便GC继续下次工作
    最后,把回收的空间放到空闲列表上面,方便后面的程序直接申请空间使用

优点

  • 可以解决对象循环引用的回收操作

缺点

  • 回收空间地址不连续,空间的碎片化:由于当前我们回收的对象在地址上是不连续的,从而造成回收后他们分散在各个角落,一旦新的空间申请大于或者小于当前的空间碎片,会造成空间的浪费或空间不足
  • 不能立即回收垃圾对象
标记整理算法实现原理

标记整理可以看做是标记清除的增强
标记阶段的操作和标记清除一致
清除阶段会先执行整理,移动对象位置
优点

  • 减少碎片化空间

缺点

  • 不能立即回收垃圾对象

认识V8

  • 主流的js执行引擎
  • 采用即时编译,之前很多js引擎都需要将代码转为字节码,然后才能去执行,V8是直接将代码编译为可执行的机器码,速度上快了很多
  • V8内存设有上限,64位操作系统上限不超过1.5G,32位系统不超过800M

V8垃圾回收策略

  • 采用分代回收的思想
  • 内存分为新生代、老生代
  • 针对不同代的算法采用不同的GC算法

V8中常用的GC算法

  • 分代回收
  • 空间复制
  • 标记清除
  • 标记整理
  • 标记增量

V8如何回收新生代对象

V8内存分配
新生代对象(64位32M | 32位16M) / 老生代的对象
新生代指的是存活时间较短的对象

新生代对象的回收实现

主要用复制算法+ 标记算法,将储存新生代对象的空间分为两个等大小的空间,使用空间叫做From ,空闲空间叫做To

  • 所有的所动对象都在From里面
  • 当From存储到一定量时,触发GC操作
  • 标记整理后,把标记的活动对象copy到To
  • 然后把To Copy到From,From到To进行空间置换,达到From的空间释放
    细节说明
  • copy过程发现变量晋升,
    晋升含义: 某个对象使用空间在老生代对象中也出现过,将新生代移到老生代储存
    晋升触发时机:
  • 一轮GC后还存活的新生代需要晋升
  • To空间的使用率超过25%
老生代回收说明

老生代对象说明

  • 存在右侧的老生代区,64位1.4G,32位700M
  • 存活时间较长的对象

回收实现
标记清除,标记整理,增量标记算法

步骤

  1. 首先标记清除
  2. 当想把新生代放入老生代的时候,并且当老生代空间不足的时候,触发标记整理
  3. 最后采用增量标记进行效率优化
细节对比
  • 新声带区域垃圾回收就是使用空间换时间
  • 老生代不适合复制算法(耗时,空间占用大)

代码优化相关

  • 慎用全局变量
  • 缓存全局变量
function getBtn(){
  let btn1 = document.getElementById('btn1')
  let btn2 = document.getElementById('btn2')
}
function getBtn(){
  let doc = document
  let btn1 = doc.getElementById('btn1')
  let btn2 = doc.getElementById('btn2')
}
  • 通过原型对象增加附加方法
function F1(){
  this.foo = function (){
      console.log(111)
  }
}
f1 = new F1()

function F2(){}
F2.property.foo =  function (){
      console.log(111)
}
f2 = new F2()
  • 避开闭包陷阱
function foo(){
  let el = document.getElementById('btn')
  el.onclick = function(){
    console.log(el.id)
  }
  el = null // 在函数内部删除对dom的引用,从而避免内存泄漏
}
foo()
  • 避免属性访问方法使用
    js不需要属性的访问方法,所有属性都是外部可见的
    使用属性访问方法只会增加一层重定义,没有访问的控制力
function Person(){
  this.name = "coder"
  this.age = 18
  this.getAge = function (){
    return this.age
  }
}
const p1 = new Person()
const pAge = p1.getAge()

function Person(){
  this.name = "coder"
  this.age = 18
}
const p1 = new Person()
const pAge = p1.age
  • For循环优化
const btns = document.getElementByClass('.btn')
for(var i ; i< btns.length;i++){
  console.log(i)
}
for(var i ;len=btns.length; i< len;i++){
  console.log(i)
}
  • 采用最优循环方式
    for / forEach / for...in
var arrList = [1,2,3,4,5]
// 最优
arrList.forEach(function(item){
  console.log(item)
})
// 第二
for(var i = arrList.length; i ;i--){
  console.log(arrList[i])
}
// 第三
for(var i in arrList){
  console.log(arrList[i])
}
  • 文档碎片优化节点添加
    节点添加操作必然会有回流和重绘
for ( var i = 0; i<10; i++ ){
  var oP = document.createElement('p')
  oP.innerHTML = i
  document.body.appendChild(oP)
}

const fragEle = document.createElement('p')
for ( var i = 0; i<10; i++ ){
  var oP = document.createElement('p')
  oP.innerHTML = i
  fragEle.appendChild(oP)
}
document.body.appendChild(fragEle)
  • 克隆优化节点操作
    当新增节点的时候,可以找当前已经存在的相似节点clone后添加到界面上
for ( var i = 0; i<3; i++ ){
  var oP = document.createElement('p')
  oP.innerHTML = i
  document.body.appendChild(oP)
}

var oldP = document.getElementById('box1')
for ( var i = 0; i<3; i++ ){
  var newP = oldP.cloneNode(false)
  newP.innerHTML = i
   document.body.appendChild(newP)
}
  • 直接量替换Object操作
    当定义一些对象和数组的时候,可以直接通过new的方式 ,也可以通过字面量
const a = new Array()
a[0] = 1
a[1] = 2
a[2] = 3

const a = [1,2,3]

相关文章

  • JS性能优化——JavaScript语言的优化

    拉勾大前端的学习笔记,仅作为学习记录 内容概要 内存管理 垃圾回收与常见GC算法 V8引擎的垃圾回收 Perfor...

  • 前端性能优化

    js性能小贴士——优化循环 前端网页与js性能优化 我总结的js性能优化的小知识 提高 web 应用性能之 Jav...

  • 前端性能 优化 大全

    js性能小贴士——优化循环 前端网页与js性能优化 我总结的js性能优化的小知识 提高 web 应用性能之 Jav...

  • 前端进阶(9) - js 性能优化利器:prepack

    js 性能优化利器:prepack 1. js 性能优化 js 性能优化不外乎从三个角度入手: 1.1 开发者在编...

  • 前端性能优化

    前端性能优化 下面是我认知的前端性能优化的策略,本书主要着手 JavaScript 优化展开阐述。 JavaScr...

  • react性能优化

    React性能优化 javascript react.js hepeguo 2016年08月12日发布 当大家考虑...

  • Web程序性能优化——asm.js和WebAssembly

    asm.js asm.js是JavaScript语言中一个可以高度优化的子集。通过避免JavaScript引擎某些...

  • JavaScript 性能优化

    介绍 性能优化是不可避免的哪些内容可以看做性能优化无处不在的前端性能优化 JavaScript内存管理 为什么要使...

  • JavaScript动态加载js和css

    动态加载js 参考:javascript 性能优化 动态加载css 参考: 动态加载 css 方法实现和深入解析 ...

  • 如何进行网站性能优化

    网站性能优化“六步法则”:一、网页内容优化;二、服务器优化;三、Cookies优化;四、 CSS优化;五、JS优化...

网友评论

      本文标题:JS性能优化——JavaScript语言的优化

      本文链接:https://www.haomeiwen.com/subject/rwfrbktx.html