JS在浏览器上的性能分析(一)脚本的下载与运行

前言

JS在浏览器上的性能,可以认为是开发者所面临的最严重的可用性问题。JS的阻塞特性使得浏览器在执行JS代码时不能同时做其他任何事情,而大多数浏览器使用单一的进程来处理用户界面(UI)刷新和JS脚本执行,所以同一时刻只能做一件事,JS执行过程耗时越久,浏览器所等待的响应时间越长。在这篇文章中,你将会学到浏览器脚本文件下载和执行的阻塞特性和如何对其进行优化。使用script元素的属性以及一些常用手段使脚本无阻塞加载。本篇文章参考了《高性能javascript》及《javascript模式》里的内容。

默认阻塞的脚本

script标签

script标签每次出现都会霸道的让页面等待脚本的解析和执行,同样,当使用script的src属性加载页面时,浏览器必须先花时间下载外链文件中的代码,然后解析并执行。在这个过程中,页面渲染和用户交互是完全被阻塞的。

浏览器之所以产生这样的行为,是因为当前HTML页面无从知晓JS的动作:JS可能会向document里添加内容、引入其它元素、甚至关闭标签。

所以浏览器会先(下载和)执行JS代码,然后才解析和渲染页面。

请看下面的代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title></title>
</head>
<body>
hello world
<script>while (1){}
</script>
<div style="width: 300px;height: 50px;border: 1px solid red"></div>
</body>
</html>

不要妄想页面会输出hello world,然后由于循环而“卡壳”。事实上页面不会输出任何东西,因为脚本的执行一直占有浏览器进程,使得界面无法渲染。

优化

想要使页面得到更快的渲染,一是优化脚本的执行速度,例如使用观察者模式减少初始化代码的执行数量,这并不在这篇文章的阐述范围之内。请牢记,默认状态下,所有的脚本必须被执行后,页面才会开始渲染。即在浏览器解析页面之前,须先读取并执行脚本。我们现在试着对脚本的下载过程进行优化。

现代浏览器都允许并行下载JS文件,但JS文件的下载过程仍然会阻塞其他比如图片资源的下载。尽管JS文件的下载并不会相互影响,但是浏览器会等待全部的JS代码下载完成才执行之。

优化的关键在于使各种资源的下载并行执行,下面是分条列项的几点注意事项:

1. 雅虎特别性能小组提出的优化JS的首要规则:将脚本放在底部

这样做可以防止脚本代码的下载与执行阻塞页面其它资源,比如图片的下载(下载往往需要更多的时间),以尽量减少对整个页面下载的影响

如果把脚本文件放在头部,那么需要等到所有脚本下载并执行完毕后才能下载图片等其他资源,这是多么的可怕啊。但如果我们把脚本放在body标签的尾部,则可以是其它资源的下载和脚本的下载与执行并发进行,能够大大加快页面的下载速度。

2. 减少script标签的数量,减少延时
3. 不要把内嵌脚本紧跟在link标签后面
    <link ref="test.css" rel="stylesheet"><script>// do something</script>

这样做会导致页面阻塞去等待样式表的下载,因为需要确保内嵌脚本在执行时能获得最准确的样式信息。

4. 减少外链脚本文件的数量——将多个外链JS文件合并成一个以减少HTTP开销

无阻塞的脚本

无阻塞脚本意味着脚本的下载和执行不阻塞其他资源的下载和页面的解析

script属性

可以通过设置script标签的defer和async属性使其拥有不阻塞的特性,它们仅对外部链接的script有效。
带有async或者defer的script都会立刻下载并不阻塞页面解析,它们的不同之处在于script执行的时机。

defer
<script src="test.js" defer></script>

会确保按脚本在页面中出现的顺序来执行,它们执行的时机是在页面解析完后, DOMContentLoaded事件之前,这时脚本可以获得页面的所有元素。如下事例代码:

html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title></title><script src="test.js" defer></script><script src="test2.js" defer></script>
</head>
<body>
<div id='test' style="width: 300px;height: 50px;border: 1px solid red">hello world</div>
<script>alert('阻塞加载的script');
</script>
<script>window.onload =function () {alert('页面加载完毕');};
</script>
</body>
</html>

test1.js

var div = document.getElementById('test');
alert(div.innerHTML);

test2.js

alert('我是test2.js');

依次输出:

加载阻塞的javascript
hello world
我是test2.js
页面加载完毕
async

async是html5中的新属性。带有async的script,一旦下载完成就开始执行(当然是在window的onload之前)。这意味着这些script 可能不会按它们出现在页面中的顺序来执行,如果你的脚本互相依赖并和执行顺序相关,就有很大的可能出问题。由于这依赖于下载文件的大小,我就不进行测试了。

动态脚本元素

类似于JSONP的形式,动态创建脚本元素并加载到页面中。这种技术的重点在于该元素被添加到页面时开始下载,文件的下载和执行过程不会阻塞页面其它进程。

<script>var script = document.createElement('script');script.src = 'test2.js';document.getElementsByTagName('head')[0].appendChild(script);
</script>

但值得注意的有两点:

1. 把新创建的script标签添加到head标签里可以防止“操作已终止错误”
2. 下载完成后,返回的代码会立即执行,所以你需要通过onload事件控制加载顺序和依赖关系
script.onload = function () {}

XMLHttpRequest也是一种办法,但因为它无法实现跨域,不能从CDN上获取文件,因此不常使用。而像CSS等文件,已经是并行下载,不会阻塞页面其它进程,故没有必要动态加载CSS文件。

小结

虽然无阻塞脚本技术可以动态加载很多文件,但为了减小HTTP的开销,还是需要尽量减少文件数。

JS在浏览器上的性能分析(一)脚本的下载与运行相关推荐

  1. 使用midi.js在浏览器上播放mid音频文件

    以下为使用midi.js在浏览器上实现播放mid文件的代码: 首先安装midi.js npm install --save midi.js 然后下载  acoustic_grand_piano-ogg ...

  2. matlab仿真环境运行,ADMIRE 飞行仿真模型,Matlab环境中运行,可实现快速 ,性能分析 274万源代码下载- www.pudn.com...

    文件名称: ADMIRE下载  收藏√  [ 5  4  3  2  1 ] 开发工具: Others 文件大小: 18800 KB 上传时间: 2017-04-18 下载次数: 0 详细说明:飞行仿 ...

  3. 浏览器调试工具网页性能分析中的使用

    IE.chrome.firefox等按F12可以掉出它们自带的页面调试工具,作为测试当然不能非常精通在页面上修改样式,调试页面jsp,js,但是却可以很轻松的使用它来分析网页的性能优化项. 基础篇 现 ...

  4. leaflet 结合 d3.js 实现 geojson 数据地形剖面分析(附源码下载)

    前言 leaflet 入门开发系列环境知识点了解: leaflet api文档介绍,详细介绍 leaflet 每个类的函数以及属性等等 leaflet 在线例子 leaflet 插件,leaflet ...

  5. 网站性能分析(下)-让网站并行加载但顺序执行JS

    如果网站不支持JavaScript,复杂的功能将无法正常工作.在开发当中通常有几个脚本会写在HTML文件的头部.你嵌入的越多,网站的速度潜在的变得越慢.因此提高并行加载速度变得非常有必要,在前面的文章 ...

  6. 在浏览器上也能训练神经网络?TensorFlow.js带你玩游戏~

    How to train neural network on browser 无论你是刚开始深度学习,亦或是个老练的老手,建立一个神经网络的训练环境有时都会很痛苦.让神经网络的训练像加载一个网页,然后 ...

  7. 浏览器页面性能分析指南(chrome)

    1.首先我们需要无痕模式打开一个新的chrome标签,可以按Ctrl+Shift+N开启一个无痕模式的chrome 选择无痕模式是为了不让其他的插件干扰你 我们先写一个html的小例子,里面有一些js ...

  8. DevTools 实现原理与性能分析实战

    作者:vivo 互联网浏览器内核团队-Li Qingmei 一.引言 从 2008 年 Google 释放出第一版的 Chrome 后,整个 Web 开发领域仿佛被注入了一股新鲜血液,渐渐打破了 IE ...

  9. Chrome DevTools 实现原理与性能分析实战

    点击上方 前端Q,关注公众号 回复加群,加入前端Q技术交流群 作者:vivo 互联网浏览器内核团队-Li Qingmei 一.引言 从 2008 年 Google 释放出第一版的 Chrome 后,整 ...

最新文章

  1. NYOJ737 石子合并(一)区间动态规划
  2. 在Linux上安装Memcached服务(自己测试过了)
  3. linux的文件link占用空间的差别,Linux重要知识点汇总——磁盘与文件系统管理
  4. Twitch未来五年的视频编码战略:从H.264到 AV1
  5. 效果直逼flash的Div+Css+Js菜单
  6. excel制作录入和查询系统_Excel进销存管理系统,完整函数应用,出入查询库存更新自动显示...
  7. [JZOJ4640] 【GDOI2017模拟7.15】妖怪
  8. Axure RP 9安装与使用
  9. 解决下载了pygame后,pycharm依然报错No module named ‘pygame
  10. python爬取搜狐最新时政新闻数据
  11. 2019 TIP之ReID:Learning Modality-Specific Representations for Visible-Infrared Person Re-Identificati
  12. [-Flutter趣玩篇-] 出神入化的Align+动画
  13. 35页智慧安防小区管控系统 解决方案
  14. [再寄小读者之数学篇](2014-06-23 向量公式)
  15. OkHttp3封装第二版
  16. Inventor SDK入门---用API创建具有旋转和拉伸特征的零件
  17. 详解下一代网络(NGN)
  18. 安装Apache服务器遇见.dll丢失等问题解决
  19. Es5的几种继承方式
  20. 反相放大器和同相放大器的过程和区别及选择方式概述

热门文章

  1. Atomikos 分布式事务的使用
  2. crm系统如何帮助企业提升客户满意度?
  3. ST电机库v5.4.4源代码分析(8): 旋编怎么对齐
  4. [samtools]flagstat命令简介
  5. scala中伴生对象和伴生类
  6. 迷宫问题 (下) 使用Quene 实现
  7. matlab中 晶闸管整流桥导通角_逆变角如何设置,双反星型整流电路讲解.ppt
  8. Babylon.js 第34章 合并网格
  9. LLVM RISCV编译器编译QuickStart
  10. 马尔可夫链蒙特卡罗算法(MCMC方法)