javascript的高性能优化(前端技术)
Posted Mr song song
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript的高性能优化(前端技术)相关的知识,希望对你有一定的参考价值。
阅读目录
众所周知浏览器是使用单进程处理UI更新和javascript运行等多个任务的,而同一时间只能有一个任务被执行,如此说来,JavaScript运行了多长时间就意味着用户得等待浏览器响应需要花多久时间。
从认知上来说,解析器解析一个界面的时候都是从上至下依次解析的,这就是说界面上出现多少个<script>标签(不管是内联还是外部文件),页面下载和解析必须停止等待脚本下载完成并运行完成(注意这里包括运行),这个过程当中,页面解析和用户交互是被完全阻塞的。
Javascript第一条定律:将脚本放在底部。
大家都知道,浏览器在遇到<body>标签之前,不会渲染页面中的任何部分,如果我们把<script>标签全部放在<body>标签之前,大家想想界面是不是一片空白,直至浏览器将所有js都下载并执行后才会去渲染页面,这也就是为什么要将所有<script>标签放在尽可能接近<body>标签底部也就是</body>前的原因。
Javascript第二条定律:将脚本成组打包。
减少引用外部脚本文件的数量,大家相信都会看到一些大型网站需要多次请求JavaScript文件时会将这个文件整合成一个文件,因为这样只需要一个<script>标签而减少性能损失。
书中介绍了运行一个<script>标签来加载两个js文件(但是自己没有试验成功,如果有知道怎么用的,可以告知我,谢谢!)
在此特意说明一下
为什么很多人特别喜欢用外部文件来写js而不用内联js,这是因为1)外部文件易于管理2)浏览器有缓存外部文件的功能,同样一个js文件如果被多个界面共享使用,第二个使用的可以直接从缓存中拿而不用从远程服务器上去下载,省去了好多时间及流量呀
为什么许多人会用CDN(Content Delivery Network)来加载公用js比如说jquery.js,这是因为从别的网站比如说jQuery官网下载jQuery占有的是别人服务器的资源,减轻了本地服务器的负载,节省网站分布式架构的支出成本和运维成本。
上文中讲了将多个js文件打包成一个js文件,可以提高性能,可以试试用Yahoo! Combo handler ,这篇文章介绍了一下http://www.ooso.net/archives/458 不过百度一下js打包工具一大堆,大家可以任意发挥哦
总归一句话就是加载js的时候会阻塞页面渲染,那怎么样让脚本不阻塞页面渲染呢,唯一的方法就是在window.onload发生后开始下载js
Javascript第三条定律:使用非阻塞方式下载js。
第一种方法:为script增加了一个defer属性,defer属性指定的script指明脚本不打算修改DOM,所以代码可以稍后执行。但是defer并不是所有浏览器都支持的。当defer指定的脚本文件被下载时,它不会阻塞浏览器的其它处理过程,所以事实上defer指定的脚本文件是可以与页面中的其它资源并行下载的。任何被指定为defer的脚本文件一定会在DOM加载完成之后才会被执行,也就是在onload事件之前被执行。
第二种方法:动态创建脚本也就是通过js创建script标签指定它的src来加载脚本文件,这种方法使得脚本下载和运行不会阻塞其它页面处理程序,所以你甚至可以把这种动态创建脚本的文件放在head标签当中都没有关系。
动态创建脚本的js如下图所示:
上述动态创建的脚本只要一指定它的src并append到document中,它就会自动执行里面的代码,那怎么样让它加载完成之后执行回调函数或者说如果我要加载多个js文件合格保证它们的顺序呢
看代码吧! 哈哈(因为动态加载的js,浏览器不保证加载的顺序)
另外一种以非阻塞方式获得脚本文件的方法就是使用XHR(XmlHttpRequest脚本注入)
这种方法的主要优点是你可以下载不立即执行的脚本文件,但是缺点就是你要动态加载的js文件必须与当前运行的页面在同一个域中。
下面介绍几个动态加载的脚本库
LazyLoad--可以下载多个脚本文件并保证在所有浏览器上保证顺序执行。(虽然可以动态加载多个文件,但还是建议尽可能的减少文件数量,因为每个下载仍然是一个单独的HTTP请求)
Labs.js 它的script方法用于加载js文件,wait方法用于等待文件下载并运行之后执行的回调函数,通过wait方法允许你哪些文件应该等待其它文件,具体用法可以参照labs使用方法
杂谈
对于任何一种编程语言来说,数据存储的位置关系到访问速度!
在JavaScript中的直接量包括字符串string、数字number、布尔值boolean、对象object、数组array、函数function、正则表达式regular expression、空值null、未定义数组undefined。而数组项则需要通过数组的数字索引来访问,对象通过字符串进行索引来访问其成员(这里顺便提一句因为数组项是通过数字进行索引、对象成员是通过字符串进行索引,所以这也就是为什么访问对象成员比访问数组项更慢的原因)。
总结一句话就是说直接量和局部变量的访问速度要远已于数组项和对象成员,所以我们应该尽量使用直接量和局部变量,尽量限制使用数组项和对象成员。
了解过JavaScript原型链和闭包的都知道在JavaScript中每个函数事实上就是对象,每个函数内部都会有一个Scope属性,这个属性包含被创建的作用域中对象的集合,所以事实上内部Scope属性就是函数的作用域。在函数运行时,会建立一个运行期上下文(运行期上下文事实上就是函数运行时的环境,对于函数的每次运行而言,运行期上下文都是独一的,函数执行完毕运行期上下文将被销毁,也就是说多次运行同一个函数就会创建多个运行期上下文)。
当函数运行期上下文确定后,它的作用域将被初始化(作用域初始化包括函数参数、函数内部变量、this),作用域初始化之后将被作为激活对象推入作用域链的前端。(事实上这就是原型链的原理,js就是通过原型链来实现继承,通过闭包来实现成员的公有和私有),这也是为什么访问全局变量是最慢的,因为全局变量它是处于运行期上下文作用域链的最后一个位置。
以上是关于javascript的高性能优化(前端技术)的主要内容,如果未能解决你的问题,请参考以下文章