JavaScript性能优化-工具及代码优化(11)

Part2 · 前端工程化实战

JavaScript性能优化-工具及代码优化

文章说明:本专栏内容为本人参加【拉钩大前端高新训练营】的学习笔记以及思考总结,学徒之心,仅为分享。如若有误,请在评论区支出,如果您觉得专栏内容还不错,请点赞、关注、评论。共同进步!

上一篇:【JavaScript性能优化-内存管理】

本篇主要内容是JavaScript的性能优化,包含Performance工具及JavaScript代码优化

超长文、多图预警!!!超长文、多图预警!!!

一、Performance工具

1.Performance工具介绍

使用Chrome DevTools的performance面板可以记录和分析页面在运行时的所有活动。

为什么我们需要使用Performance工具,其原因有以下几点:

  • GC的目的是为了实现内存空间的良性循环
  • 良性循环的基石是合理使用
  • 时刻关注才能确定是否合理
  • 由于ECMAScript中未向开发者提供操作内存空间的API
  • Performance工具提供了多种监控方式

Performance使用步骤为:

  1. 打开浏览器输入目标地址
  2. 进入开发人员工具面板(F12),选择performance
  3. 开启录制功能,访问具体界面
  4. 执行用户行为,一段时间后停止录制
  5. 分析界面中记录的内存信息

2.内存问题的体现

内存问题的体现分为外在表现和内在表现。

内存问题的外在表现:

  • 页面出现延迟加载或经常性暂停
  • 页面持续性出现糟糕的性能
  • 页面的性能随时间延长越来越差

内存问题的内在表现:

  • 内存泄漏:内存使用持续升高
  • 内存膨胀:在多数设备上都存在性能问题
  • 频繁垃圾回收:通过内存变化图进行分析

3.监控内存的几种方式

3.1任务管理器监控内存

打开浏览器,按键【Shift】+ 【Esc】,调出浏览器任务管理器。找到我们的目标标签页,刚开始可能没有JavaScript内存,可以在目标标签页任务上右键,然后选择JavaScript内存。

记录JavaScript内存(JavaScript堆占用的内存,表示界面中所有可达对象占用的内存)及内存占用空间(原生内存,DOM节点占用的内存),点击按钮,记录每次内存的变化。

在这里插入图片描述

3.2Timeline记录内存

上述浏览器任务管理器更多的是用于判断当前脚本是否存在内存问题,而不能具体定位到问题。我们使用Timeline时间线记录内存变化,更精确的记录到内存变化。

在这里插入图片描述

3.3堆快照查找分离DOM

什么是分离DOM

  • 界面元素存货在DOM树上
  • 垃圾对象时的DOM节点(当前DOM从存活的DOM树上分离,且js中没有应用这个DOM)
  • 分离状态的DOM节点(当前DOM节点从当前DOM树分离,但js中还在应用它)

在这里插入图片描述

在点击按钮后,DOM中生成了分离的DOM,造成内存空间的浪费,因此我们需要将代码中的temEle置空,这样让GC对垃圾进行回收即可。

3.4判断是否存在频繁GC

为什么要确定频繁垃圾回收

  • GC工作时应用程序是停止的
  • 频繁且过长的GC会导致应用假死
  • 用户使用中感知应用卡顿

确定频繁的垃圾回收:

  • Timeline中频繁的上升下降
  • 任务管理器中的数据频繁增加减小

二、代码优化

1.代码优化介绍

如何精准测试JavaScript性能:

  • 本质上就是采集大量的执行脚本进行数学统计和分析
  • 使用基于Benchmark.js的https://jsbench.me/使用

在这里插入图片描述

代码需要优化的原因:

  • JavaScript中的内存管理自动完成
  • 执行引擎会使用不同的GC算法
  • 算法工作的目的是为了实现内存空间良性循环
  • Performance工具检测内存变化
  • JavaScript是单线程机制的解释性语言

2.慎用全局变量及缓存全局变量

全局变量的特点:

  • 全局变量挂载在window下
  • 全局变量至少有一个引用计数
  • 全局变量存货更久,但持续占用内存

全局查找相关:

  • 目标变量不存在于当前作用域内,通过作用域链向上查找
  • 减少全局查找降低的时间消耗
  • 减少不必要的全局变量定义
  • 全局变量数据局部化

慎用全局变量:

  • 全局变量定义在全局执行上下文,是否有作用域链的顶端
  • 全局执行上下文一直存在于上下文执行栈,指导程序退出
  • 如果某个局部作用于初夏了同名的变量则会遮蔽或午饭全局

慎用全局变量代码演示:

function fn() {
  name = 'lg'
  console.log(`${name} is a coder`)
}

fn() 


function fn() {
  const name = 'lg'
  console.log(`${name} is a coder`)
}

fn() 

测试结果:

在这里插入图片描述

var i, str = ''
for (i = 0; i < 1000; i++) {
  str += i
}

for (let i = 0; i < 1000; i++) {
  let str = ''
  str += i
}

在这里插入图片描述

缓存全局变量代码演示:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>缓存全局变量</title>
</head>
<body>
  <input type="button" value="btn" id="btn1">
  <input type="button" value="btn" id="btn2">
  <input type="button" value="btn" id="btn3">
  <input type="button" value="btn" id="btn4">
  <p>1111</p>
  <input type="button" value="btn" id="btn5">
  <input type="button" value="btn" id="btn6">
  <p>222</p>
  <input type="button" value="btn" id="btn7">
  <input type="button" value="btn" id="btn8">
  <p>333</p>
  <input type="button" value="btn" id="btn9">
  <input type="button" value="btn" id="btn10">

  <script>
    function getBtn() {
      let oBtn1 = document.getElementById('btn1')
      let oBtn3 = document.getElementById('btn3')
      let oBtn5 = document.getElementById('btn5')
      let oBtn7 = document.getElementById('btn7')
      let oBtn9 = document.getElementById('btn9')
    }

    function getBtn2() {
      let obj = document
      let oBtn1 = obj.getElementById('btn1')
      let oBtn3 = obj.getElementById('btn3')
      let oBtn5 = obj.getElementById('btn5')
      let oBtn7 = obj.getElementById('btn7')
      let oBtn9 = obj.getElementById('btn9')
    }
  </script>

</body>
</html>

测试结果:

在这里插入图片描述

3.通过原型对象添加附加方法

代码演示:

var fn1 = function() {
  this.foo = function() {
    console.log(11111)
  }
}

let f1 = new fn1()


var fn2 = function() {}
fn2.prototype.foo = function() {
  console.log(11111)
}

let f2 = new fn2()

测试结果:

在这里插入图片描述

4.避开闭包陷阱

关于闭包:

  • 闭包是一种强大的语法
  • 闭包使用不当很容易出现内存泄漏
  • 不要为了闭包而闭包

代码示例:

function test(func) {
  console.log(func())
}

function test2() {
  var name = 'lg'
  return name
}

test(function() {
  var name = 'lg'
  return name
})

test(test2)

5.避免属性访问方法使用

  • JavaScript不需要属性的访问方法,所有属性都是外部可见的
  • 使用属性访问方法只会增加一层重定义,没有访问的控制力

代码示例:

function Person() {
  this.name = 'icoder'
  this.age = 18
  this.getAge = function() {
    return this.age
  }
}

const p1 = new Person()
const a = p1.getAge()



function Person() {
  this.name = 'icoder'
  this.age = 18
}
const p2 = new Person()
const b = p2.age

测试结果:

在这里插入图片描述

6.For循环优化及选择最优循环方法

代码示例:

var arrList = []
arrList[10000] = 'icoder'

for (var i = 0; i < arrList.length; i++) {
  console.log(arrList[i])
}

for (var i = arrList.length; i; i--) {
  console.log(arrList[i])
}

测试结果:

在这里插入图片描述

选择最优循环方法

代码示例:

var arrList = new Array(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])
}

测试结果(forEach效率最高):

在这里插入图片描述

7.文档碎片优化节点添加、克隆优化节点操作

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>优化节点添加</title>
</head>
<body>
  <script>

    for (var i = 0; i < 10; i++) {
      var oP = document.createElement('p')
      oP.innerHTML = i 
      document.body.appendChild(oP)
    }

    const fragEle = document.createDocumentFragment()
    for (var i = 0; i < 10; i++) {
      var oP = document.createElement('p')
      oP.innerHTML = i 
      fragEle.appendChild(oP)
    }

    document.body.appendChild(fragEle)

  </script>
</body>
</html>

测试结果:

在这里插入图片描述

克隆优化节点操作

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>克隆优化节点操作</title>
</head>
<body>
  <p id="box1">old</p>

  <script>

    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)
    }

  </script>

</body>
</html>

测试结果:

在这里插入图片描述

8.直接量替换new Object

代码示例:

var a = [1, 2, 3]

var a1 = new Array(3)
a1[0] = 1
a1[1] = 2
a1[2] = 3

测试结果:
在这里插入图片描述

9.堆栈中的JS执行过程

let a = 10;
function foo(b) {
    let a = 2;
    function baz(c) {
        console.log(a+b+c);
    }
    return baz
}
let fn = foo(2);
fn(3);

在这里插入图片描述

10.减少判断层

function doSomething(part, chapter) {
    const parts = ['ES2015', '工程化', 'Vue', 'Reach', 'Node'];
    if (part) {
        if (parts.includes(part)) {
            console.log('属于当前课程')
            if (chapter > 5) {
                console.log('您需要提供VIP身份')
            }
        }
    } else {
        console.log('请确认模块信息')
    }
}

doSomething('ES2015', 6)

function doSomething2(part, chapter) {
    const parts = ['ES2015', '工程化', 'Vue', 'Reach', 'Node'];
    if (!part) {
        console.log('确认模块信息')
        return
    }
    if (!parts.includes(part)) return;
    console.log('属于当前课程')
    if (chapter > 5) {
        console.log('您需要提供VIP身份')
    }
}

doSomething2('ES2015', 6)

11.减少作用域链查找层级

代码示例:

var name = 'zce';

function foo() {
    name = 'zce666'  // 这里的name是全局的
    function baz() {
        var age = 28
        console.log(age)
        console.log(name)
    }
    baz()
}
foo()

var name = 'zce';

function foo() {
    var name = 'zce666'  // 这里的name是全局的
    function baz() {
        var age = 28
        console.log(age)
        console.log(name)
    }
    baz()
}
foo()

测试结果:

在这里插入图片描述

12.减少数据读取次数

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>减少数据读取次数</title>
</head>
<body>
	<div id="skip" class="skip"></div>
	<script>
		var oBox = document.getElementById('skip')
		function hasEle(ele, cls) {
				return ele.className === cls
    }
    
    function hasEle(ele, cls) {
		    var className = ele.className
		    return className === cls
    }

    console.log(hasEle(oBox, 'skip'))
	</script>
</body>
</html>

测试结果:

在这里插入图片描述

13.字面量与构造式

代码示例:

var test = () => {
    let obj = new Object();
    obj.name = 'zce';
    obj.age = '28';
    obj.slogan = '我为前端而活'
    return obj
}

var test = () => {
    let obj = {
        name: 'zce',
        age : '28',
        slogan: '喔喔前端而活'
    }
    return obj
}

console.log(test())

测试结果:

在这里插入图片描述

14.减少循环体中活动

代码示例:

var test = () => {
    var i
    var arr = ['zce', 28, '我为前端而活']
    for (let i = 0; i < arr.length; i++) {
        console.log(arr[i])
    }
}

var test = () => {
    var i
    var arr = ['zce', 28, '我为前端而活']
    var len = arr.length
    for (let i = 0; i < len; i++) {
        console.log(arr[i])
    }
}

测试结果:

在这里插入图片描述

15.惰性函数与性能

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Title</title>
</head>
<body>
	<button id="btn"></button>
	<script>
		var oBtn = document.getElementById('btn');
		function foo() {
        console.log(this)
    }
    
    function addEvent(obj, type, fn) {
		    if (obj.addEventListener()) {
		        obj.addEventListener(type, fn, false)
		    } else if (obj.attachEvent) {
		        obj.attachEvent('on'+type, fn)
		    } else {
		        obj['on' + type] = fn
		    }
    }


    function addEvent(obj, type, fn) {
        if (obj.addEventListener()) {
            addEvent = obj.addEventListener(type, fn, false)
        } else if (obj.attachEvent) {
            addEvent = obj.attachEvent('on'+type, fn)
        } else {
            addEvent = obj['on' + type] = fn
        }
        return addEvent
    }
    
	</script>
</body>
</html>

16.减少声明及语句数

代码示例:

var test = () => {
    let w = 200
    let h = 300
    return w * h
}

var test = () => {
    return 200 * 300
}

17.采用事件绑定

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Title</title>
</head>
<body>
<ul id="ul">
	<li>Leo</li>
	<li>28</li>
	<li>我为前端而活</li>
</ul>
<script>
	var list = document.querySelectorAll('li')
	function showText(ev) {
      console.log(ev.target.innerHTML)
  }

  for (let listElement of list) {
		  item.onclick = showText
  }
  
  var oUl = document.getElementById('ul')
	oUl.addEventListener('click', showText, true)
</script>
</body>
</html>

今日分享就到了这里,上面很多的概念性问题,要完全的理解并使用这些新的知识,需要很长一段时间。多用、多查、多做!
Part1 JavaScript部分分享完成,后面进行前端工程化的分享,共同进步!

记录:2020/11/16

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Netdata是一款Linux性能实时监测工具。Netdata是一个高度优化的Linux守护进程,它为Linux系统,应用程序,SNMP服务等提供实时的性能监测。 它用可视化的手段,将被监测者最细微的细节,展现了出来。这样,你便可以清晰地了解你的系统和应用程序此时的状况。 Netdata特点: 1.优美的界面:bootstrap框架下的控制界面 2.自定义的控制界面:你可以使用简单的HTML代码去自定义控制界面(不需要使用javascript) 3.极其的快速而高效:程序使用C进行编写(默认安装下,预计只有2%的单核CPU使用率和少许的内存使用率) 4.零配置:你只需要去安装它,接着它就会自动地监测一切数据 5.零依赖:它的静态网络文件和网络接口拥有自己的网络服务器 6.可扩展:用它自身的插件API(可以使用许多方式来制作它的插件,从bash到node.js),你可以检测任何可以衡量的数据。 7.可嵌入:它可以在任何Linux内核可以运行的地方运行 监测内容: 这是它目前检测的内容(大多数都不需要进行配置,安装后即可开始监测) 1.CPU的使用率,中断,软中断和频率(总量和每个单核) 2.RAM,互换和内核内存的使用率(包括KSM和内核内存deduper) 3.硬盘输入/输出(每个硬盘的带宽,操作,整理,利用等) 4.IPv4网络(数据包,错误,分片): TCP:连接,数据包,错误,握手 UDP:数据包,错误 广播:带宽,数据包 组播:带宽,数据包 5.Netfilter/iptables Linux防火墙(连接,连接跟踪事件,错误等) 6.进程(运行,受阻,分叉,活动等) 7.熵 8.NFS文件服务器,v2,v3,v4(输入/输出,缓存,预读,RPC调用) 9.网络服务质量(唯一一个可实时可视化网络状况的工具) 10.应用程序,通过对进程树进行分组(CPU,内存,硬盘读取,硬盘写入,交换,线程,管道,套接字等) 11.Apache Web服务器状态(v2.2, v2.4) 12.Nginx Web服务器状态 13.Mysql数据库(多台服务器,单个显示:带宽,查询/s, 处理者,锁,问题,临时操作,连接,二进制日志,线程,innodb引擎等) 14.ISC Bind域名服务器(多个服务器,单个显示:客户,请求,查询,更新,失败等) 15.Postfix邮件服务器的消息队列(条目,大小) 16.Squid代理服务器(客户带宽和请求,服务带宽和请求) 17.硬件传感器(温度,电压,风扇,电源,湿度等) 18.NUT UPSes(负载,充电,电池电压,温度,使用指标,输出指标)
SQL注入的原理 什么SQL注入 将SQL代码插入到应用程序的输入参数中,之后,SQL代码被传递到数据库执行。从而达到对应用程序的攻击目的。 注入原理 常见攻击方法 检测是否可以注入【检测注入点】 示例:http://192.168.0.1/temp.aspx?id=a or 1=1-- 如果上面语句可以执行说明可以实现注入,则可以 利用系统过程、系统表注入数据库 示例【给系统添加一个用户,黑客可以实现远程登录控制服务器】:http://192.168.0.1/temp.aspx?id=1;exec xp_cmdshell 'net user admin 123456 /add' 绕过程序的限制 示例:程序中往往限制单引号的数据,但是黑客传入单引号的ASCII码 跨站点注入 在Web页面挂某些恶意的HTML、JavaScript代码 防范SQL注入 限制错误信息的输出,避免错误信息的输出使得黑客知道网站的技术实现采用什么数据库,采用什么平台 示例:在Web.config文件中设置 限制访问数据库账号的权限 在开发应用系统的时候就应该限制,给程序最小访问数据库的权限 使用参数命令传递参数 不要使用拼接字符串的方式构造SQL语句而采用参数命令 使用存储过程 存储过程在数据库中 只能执行存储过程中固定的代码 限制输入长度 防止黑客输入超大字符串,导致服务器瘫痪 防止黑客输入较长的恶意脚本等 实现方法:文本框的MaxLength属性 URL重写技术 示例: http://testWeb/news.aspx?id=111 重写成:http://testWeb/10101111.html 传递参数尽量不用字符串 http://testWeb/news.aspx?id=111 and 1=1【黑色部分给了SQL注入的机会】 SQL优化 为什么要优化 开发是对性能考虑不多【技术差、项目工期紧等原因没有考虑性能问题】 系统运行中,数据量扩大,访问量增多,蹩脚的SQL危害开始显露 低效SQL的危害 系统响应变慢,软件开发中的8秒定律,当打开一个软件或网页超过8秒时间还没有显示,则响应太慢。 死锁,当不同用户都访问某些资源的时候SQL语句不当导致死锁 客户失去信心,软件失败 低效SQL低效在哪里?  性能低下的根源  硬件原因,数据库的配置不合理,数据库的数据文件和日志文件没有分磁盘存放,会极大影响IO性能  没有建立索引,或者SQL没有走索引。在千万级数据的表上建索引是很有必要的。  SQL过于复杂,过长的SQL语句满足程序需求但是影响性能。子查询嵌套过多对性能有影响,查询关联的表特别多也影响性能  频繁访问数据等等 SQL如何被SQLServer执行的 SQL执行原理  解释:首先解释SQL语句【语法是否正确】  解析:检验语句的出现的对象是否有效【进行一个解析,要检查对象所有权的权限】  优化:【检查SQL语句是否能够使用索引,SQL语句如何执行效率高,制定一个执行计划】  编译:  执行SQL语句:【把编译过的查询要求提交并进行处理】 如何优化SQL 完善开发的管理 完善代码审核、测试机制,软件开发是艺术! 检测SQL查询的效率 语法【对IO和Time对SQL执行进行统计】: SET STATISTICS IO ON SET STATISTICS TIME ON ------------SQL代码--------- SET STATISTICS IO OFF SET STATISTICS TIME OFF 注意:在检测之前要清理缓存,因为当我们执行SQL语句的时候查出的数据会在数据库中进行缓存,重新查询会返回缓存中的信息。 DBCC DROPCLEANBUFFERS DBCC FREEPROCCACHE 经验:使用子查询嵌套不要过多,尽量使用表连接查询代替子查询,因为表连接查询效率稍高一点。 SQL优化工具 使用报表服务 通过Reporting Service查找低效SQL 选择 性能 - 批处理执行统计信息和性能相关的几个报表服务: 性能 - 对象执行统计信息 性能 - 按平均CPU时间排在前面的查询 性能 - 按平均IO次数排在前面的查询 性能 - 按总CPU时间排在前面的查询 性能 - 按IO总次数排在前面的查询 操作示范: 1. 数据引擎上点击右键—报表—标准报表—关心的

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

5coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值