前端性能之非阻塞加载js脚本

本文探讨了JavaScript脚本阻塞页面加载的问题,分析了非阻塞加载外部脚本的几种策略,如XHR Eval、XHR Injection、Script in Iframe、Script DOM Element和Script Defer,并讨论了它们的优缺点、执行顺序以及浏览器兼容性,旨在优化前端性能,减少"等待"标志,提高用户体验。
摘要由CSDN通过智能技术生成

SCRIPT标签的阻塞行为会对页面的性能产生影响,这是因为浏览器在下载脚本、解析、执行的过程中不会同时做其他事情,比如渲染页面、响应用户事件等。之所以这样做是因为正在执行的JavaScript代码可能会改变页面元素修改样式添加或者删除事件等各种操作,以及最关键的脚本之间的依赖性,浏览器必须等待当前执行的脚本执行完成之后再进行后续操作。

脚本阻塞

两种加载方式

HTML页面中的JavaScript脚本有两种方式加入
- 使用script标签内联到HTML页面,页面按从上到下的顺序执行到script标签处时执行js代码,后续HTML内容会被阻塞。
- 使用script标签的src属性将js文件从外部加载,这需要浏览器查询对应文件的缓存,如果不可用就要重新进行http请求,这样就又会产生网络延迟和下载后的解析与执行,这都会阻塞页面。

浏览器特性

一般情况下,大多数浏览器支持并行下载html、css、图片等元素,不过对于同一个域名下的资源,浏览器默认最多并行下载的个数有限制,一般是4个。另外,对于JavaScript脚本,浏览器却不支持并行下载,当下载一个脚本并解析、执行后,才能执行后一个。
浏览器之所以保证不能并行下载多个脚本,是为了防止两个有依赖的脚本在浏览器的执行顺序颠倒后,会引发变量、函数未定义的错误。同时也会更改html内容。因此,脚本必须要顺序地执行,但是这并不代表它们必须要顺序地下载。
IE8是第一个支持并行下载JavaScript脚本的浏览器,这使得页面加载多个脚本的速度加快了很多,但是这并没有解决脚本执行的阻塞问题,当A.js和B.js并行下载之后,它们依然要进行解析和顺序执行,这段时间必须要阻塞浏览器的其他行为,也就是等这段时间过了之后才能下载后续图片、css、iframe等元素。Chrome 2+和Safari 4+浏览器也是和IE8类似,会并行下载脚本但是不能
因此,最终的目的是要并行下载脚本的同时,也能下载其他元素而不会有阻塞的问题。这里都以外部脚本文件的加载来说明。

非阻塞加载外部脚本

为了避免脚本的阻塞问题,最简单的方式就是讲所有JavaScript脚本内联到HTML中,将脚本放在所有可显示元素最后面,就可以避免这个问题,但是对于大型的js文件以及缓存js文件的考虑,这个问题需要进行折中处理。针对外部的js文件请求,主要有如下几个方式进行

XHR Eval

使用XMLHTTPRequest对象从服务器异步获取js脚本文件,当响应完成后使用JavaScript语言的eval函数对响应内容进行执行。
优点:异步请求的js文件不会阻塞其他元素(图片、css等)的下载,脚本异步下载完成之后就执行。浏览器不显示”等待“。
缺点:请求的js文件必须要与主页面在同一个域名下,这对于CDN或者多域名的处理不便。不能保证执行顺序。

var xhrObj = getXHRObject();
xhrObj.onreadystatechange = function(){
   
    if(xhrObj.readyState == 4 && xhrObj.status == 200){
        //依赖文件队列处理
        eval(xhrObj.responseText);
        //后续处理
    }
};
xhrObj.open('GET', 'a.js', true);
xhrObj.send('');

一般为了保证异步加载的js文件的依赖性,需要手动保存好依赖文件队列,使其按依赖顺序执行。

XHR Injection

与XHR Eval类似,XHR Injection将异步获取的内容使用动态创建script标签的形式插入到DOM元素中去。实际测试显示使用eval方法会比这种方法的速度慢一些。

var xhrObj = getXHRObject();
xhrObj.onreadystatechange = function(){
   
    if(xhrObj.readyState == 4 && xhrObj.status == 200){
        //依赖文件队列处理
        var script = document.createElement('script');
        document.getElementsByTagName('head')[0].appendChild(script);
        script.text = xhrObj.resp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值