JS加载顺序、执行原理与性能的关系
一、JS同步加载:javascript语言是单线程机制。所谓单线程就是按次序执行,执行完一个任务再执行下一个。对于浏览器来说无法在渲染页面的同时执行JS代码。当浏览器遇到<script>标签的时候,浏览器必须先话时间下载外链的文件然后并执行,在这过程中,页面渲染和用户交互是完全被阻塞的。所以脚本会阻塞页面的渲染,直到它们全部下载并执行完成后,页面渲染才会继续。为提升性能一般解决方式如下:
1、把<script>标签放在<body>结尾处,这样尽可能减少页面阻塞。
2、尽量减少页面包含的<script>标签数量,可以把多个js文件合并打包成一个js文件,这样子做的好处就是可以最小化延迟时间将会明显的改善页面的总体性能
二、JS异步加载:又被称为非阻塞加载,浏览器在下载JS的同时,还会进行后续页面处理。
页面加载过程详见:https://www.cnblogs.com/qqinhappyhappy/p/11872670.html
1、【defer属性】:H5新属性,指明本元素所含的脚本可以延迟执行
● defer属性规定是否对脚本执行进行延迟,直到页面加载为止(页面加载之后才执行JS),不会阻塞浏览器的其他进程
● defer属性声明脚本中不会有document.write和dom修改
● 浏览器会并行下载其他有defer属性的script,而不会阻塞页面后续处理。所有的defer脚本必须保证按顺序执行的。
● defer是在onload事件执行之前被调用
● 可以用于加载外部JS也可以用在内部JS脚本
【async属性】:H5新属性,
● 相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)
● 在onload事件执行之前被调用
● async只能加载外部js脚本,不能把js书写在script标签内(W3C标准方法)
● 不能保证脚本按顺序执行
注意区分:
-
-
- 如果 async="async":脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)
- 如果不使用 async 且 defer="defer":脚本将在页面完成解析时执行
- 如果既不使用 async 也不使用 defer:在浏览器继续解析页面之前,立即读取并执行脚本
-
2、script DOM Element方法:创建script标签,插入到DOM中,然后回调
注意:这种加载方式执行完之前会阻止onload事件的触发,而现在很多页面的代码都在onload时还执行额外的渲染工作,所以还是会阻塞部分页面的初始化处理。
3、load方式:实际上就是将插入script的方法封装到函数中,并在window的onload事件中调用,这样就解决了阻塞onload事件的问题
这种方法只是把插入script的方法放在一个函数里面,然后放在window的onload方法里面执行,这样就解决了阻塞onload事件触发的问题。
5、XHR Injection(XHR 注入):通过XMLHttpRequest来获取javascript,然后创建一个script元素插入到DOM结构中。
ajax请求成功后设置script.text为请求成功后返回的responseText。
如下图的script为:
三、延迟加载
为了解决JS延迟加载的问题,可以利用异步加载缓存起来,但不立即执行,需要的时候在执行。如何进行缓存呢?将JS内容作为Image或者Object对象加载缓存起来,所以不会立即执行,然后在第一次需要的时候在执行。
JS延迟加载机制(LazyLoad):简单来说,就是在浏览器滚动到某个位置在触发相关的函数,实现页面元素的加载或者某些动作的执行。可以通过一个定时器来实现,通过比较某一时刻页面目标节点位置和浏览器滚动条高度来判断是否需要执行函数。