前端优化之无阻塞加载脚本
前言
绝大部分浏览器是采用并行方式下载组件的,但是对于外部脚本不是并行下载的。浏览器在下载或者执行脚本的过程中,不会再下载其他的内容,只有在脚本下载和执行完毕之后才会再下载其他内容。script标签的阻塞行为会对页面的性能产生负面影响,有时候为了提供更好的用户体验,我们希望脚本和其他组件一样也是可以并行下载的。怎么来解决这一问题呢?下面就来探讨一下实现无阻塞加载脚本的技术。
1.内嵌脚本程序
该技术把所有的JavaScript的程序内嵌到页面的script标签中,在代码数量比较少或者是首页的情况下可以采用这种方式。由于使用外部文件的方式,我们在加载的时候是可以缓存脚本的,会降低响应时间,所以我们大多数情况下使用的是外部文件引入方式。
2.XHR Eval
该技术使用XHR(Ajax)从服务器端获取脚本,当获取返回的脚本后,通过调用eval命令执行脚本程序。这个方法有个缺点就是必须遵循同源策略才行,也就是说请求的脚本必须和主页同时归属于相同的域下才行。
3.XHR Injection
与上一种技术类似,XHR Injection也是通过XMLHttpRequest来获取叫脚本的。与XHR Eval不同的是,XHR注入通过创建一个script DOM元素,把通过XHR获取的响应注入到创建的script DOM元素来执行脚本。这个方法也得必须遵循同源策略才行。
4.Script in Iframe
主页中的Iframe和其他组件是并行加载的,所以如果可以借用这个特点来进行脚本加载就可以实现无阻塞,其具体实现过程完全在HTML中完成。示例如下:
<iframe src="a.html" width="0" height="0" frameborder="0" id ="frame1"></iframe>
这里使用的是a.html而不是a.js,因为iframe元素返回的是HTML文档。所以我们接下来要做的就是把外部的脚本转换成内部脚本。由于浏览器跨域安全机制不允许iframe中的JavaScript跨域访问父页面,反之亦然,所以iframe得保持和主页面同域。这个方法也得必须遵循同源策略才行。
5.Script DOM Element
相对于在HTML中使用script标签来下载脚本文件使用javascript动态地创建script DOM元素并设置其src属性。通过这种方式我们就可以在我们需要的时候再加载脚本程序,也就不会阻塞其他组件的加载了。这个方法不必遵循同源策略的限制,可以跨域访问。
6.Script Defer/Script Async
这是script自带的属性,通过这些属性的设置也可以达到并行下载的目的。而且Defer还是顺序执行的,但并不是所有的浏览器都是按照顺序执行脚本的,目前只有IE支持的较好。而Script Async虽然也是异步加载脚本的,但它不具备顺序执行这个特性。
7.document.write Script Tag
这种技术是使用document.write把HTML标签script写入页面中,就像Script Defer一样也是只有IE支持的较好。虽然使用这种方法可以并行加载,但是在下载脚本时依然阻塞其他类型的资源。
以上就是一些无阻塞加载脚本的技术实现,在具体的应用中该选择哪一种技术来实现加载呢?和绝大多数技术一样,没有独立的最佳方案,真正的最佳方案取决于需求。下图是选择最佳下载技术的决策树:
具体选择哪一种技术方案,我们可以依据上面的决策树来做出选择。