无阻塞加载和defer、async
无阻塞加载
把js放在head里,浏览器是怎么去执行它的呢,是按顺序加载还是并行加载呢?在旧的浏览器下,都是按照先后顺序来加载的,这就保证了加载的js依赖不会发生问题。但是少部分新的浏览器已经开始允许并行加载js了,也就是说可以同时下载js文件,但是还是按先后顺序执行文件的。
下载是异步的没问题,但是每个javascript执行的时候还是同步的,就是先出现的script标签一定是先执行,即使是并行下载它是最后一个下载完成的,除非标有defer的script标签。任何javascript在执行的时候都会中断当前html文档解析,自然会阻止页面渲染。
javascript加载是不会影响已经渲染的页面,但是会中断html文档解析,浏览器会在javascript执行以后决定当前文档是否需要进行重新渲染或者文档重排。所以即使javascript放到最后面也会使浏览器暂停,但不影响之前已经解析出来的dom文档,此时对于用户来说是可操作的。
javascript下载完毕之后会立即执行,所有的javascript执行都会阻塞浏览器的其他行为,例如阻塞其他javascript的执行、其他的http请求的执行以及页面的解析和渲染。(html文档中外部js的下载也会阻塞浏览器的行为,但通过创建script元素动态js的下载不会,可能是认为动态的js不会改变页面效果,所以允许资源并行下载。)

图示动态脚本的下载
UI线程会根据页面里资源(资源是指css文件,图片等等)书写的先后顺序来加载资源,加载资源也就是使用http请求获取资源,像css外部文件,html文件以及图片等资源http请求处理完毕也就意味着资源加载结束,但是像外部的javascript文件的加载则不同,它的加载过程被分为两步,第一步和加载css文件和图片一样,就是执行一个http请求下载外部的js文件,但是javascript完成http操作后并不意味操作完毕,UI线程接着会执行它。js脚本的下载和执行必须是一个完整的操作,是不能被割裂的。动态js的下载不会阻塞,但执行一定会会。
浏览器为了提升用户体验,加快UI线程的执行是一个无法回避的问题,但是拆分js的下载和执行是不可行的,如是乎浏览器换了种方式,这个方式也就是在同一个时间能下载多个资源。
将常用的,稳定的静态资源统一放在一个静态资源服务器上,由统一的域名对外提供,这个域名要和主体请求的域名不一样,原理是因为浏览器只通过域名来限制连接的个数,如果一个页面里有两个不同的域的,那么并行的http请求个数也会变成两倍。有度,对DNS解析要开销,所以2个最佳。
将所有外部js代码分为UI初始化代码和其他代码,UI初始化代码是在页面加载时候执行的代码。让那些不会用于页面初始化展示的js代码的加载和执行操作通过onload事件在浏览器忙指示结束后触发,即让那些和页面加载无关的js脚本在onload方法里执行
无阻塞加载脚本的核心技术就是动态的创建script的dom节点,而且可以跨域访问。
var script=document.createElement("script");
script.type="text/javascript";
script.src="file.js";
document.getElementsByTagName("head")[0].appendChild(script);
动态脚本元素,就是说 <script> 标签不是写死在HTML中的,而是由现有的脚本生成的,因为 <script> 标签也是DOM元素的一种,而JavaScript是可以通过DOM API操作DOM的。动态脚本只有在新建的script元素被添加到html文档时开始下载,下载完立即执行。
无阻塞脚本的好处就是不会阻塞UI的执行,也不会影响其他同步js代码的执行,不无阻塞脚本改变了脚本的加载顺序,所以在使用无阻塞脚本时候一定要更加注意脚本之间的依赖关系,保证整个页面的脚本都能正常执行。
使用无阻塞脚本了,代码置于head标签还是html文档底部也就无关紧要了。
页面加载的总时间不是衡量页面加载快捷的标准,页面同步阻塞加载的时间才是衡量页面加载效率的准确标准,非阻塞脚本加载可能会增加整个页面加载的时间,但是它可以减少页面阻塞加载的时间。
脚本的异步执行,会产生前后依赖的问题。在脚本加载执行完毕后,非ie浏览器会触发该 <script> 元素的 onload 事件,ie浏览器下有onreadystatechange事件,我们可以将回调放到这个事件中处理。
每当浏览器解析到<script>标签(无论内嵌还是外链)时,浏览器会优先下载、解析并执行该标签中的javaScript代码,而阻塞其后所有页面内容的下载和渲染。(也就是说外部js的下载也会阻塞别的线程,目前有少部分浏览器支持并行下载js)
无阻塞加载脚本技术的核心就是:动态下载js脚本的时候,不会阻塞UI线程的执行。可能是因为浏览器认为动态资源不会影响页面渲染。
让script延迟和异步的两个属性:defer和async
js脚本会改变文档输入流的内容,所以执行js时会暂停页面的渲染。对于内联脚本没什么问题,因为脚本和html文档被同时加载了。但对于外部引入的脚本,脚本的下载(取决于网速)也会阻塞浏览器文档的解析和渲染,甚至会阻塞有些浏览器下载别的资源(目前有些浏览器已经实现并行下载)。所以出现defer和async属性,优化页面的显示。
defer(延迟)是html4.0中定义的,该属性使得浏览器能延迟脚本的下载,等document文档载入和解析完成后,按照他们在文档中出现顺序再去下载解析。也就是说defer属性的<script>就类似于将<script>放在body底部的效果,会在document的DOMContentLoaded事件之前执行。
将脚本放在body底部比给脚本增加defer属性让脚本延迟加载更好。
async(异步)是HTML5新增的属性,该属性的作用是让浏览器能并行下载脚本且不阻塞浏览器的文档解析和渲染,下载完成后脚本立即执行,可能无序执行,取决于下载完成的时间)
若浏览器同时支持上述两种属性且script标签同时具有这两种属性,则async属性会优于defer生效。
在不支持async属性的浏览器里,可以通过动态创建script元素并插入文档中,实现脚本的异步载入和执行:

requirejs就是使用这个方法实现的。
无阻塞加载和defer、async的更多相关文章
- js同步、异步、延时、无阻塞加载
一.同步加载 平常默认用的都是同步加载.如:<script src="http://yourdomain.com/script.js"></script> ...
- 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密
下面的图片是我使用firefox和chrome浏览百度首页时候记录的http请求 下面是firefox: 下面是chrome: 在浏览百度首页前我都将浏览器的缓存全部清理掉,让这个场景最接近第一次访问 ...
- 高性能 js -- 无阻塞加载脚本
参考: <<高性能JavaScript>> Nicbolas C. Zakas 著 javascript代码的下载和执行过程会阻塞浏览器的其他进程, 比如页面的绘制, 遇到&l ...
- 无阻塞加载js,防止因js加载不了影响页面显示
浏览器加载静态资源和js的方式都是线性加载,所以一般情况可以将js放到</body>前,防止UI线程的阻塞. 而某些时候我们既希望js在整个网页的头部就加载,又担心js阻塞导致网站加载缓慢 ...
- 高性能Javascript--脚本的无阻塞加载策略
Javascript在浏览器中的性能,可以说是前端开发者所要面对的最重要的可用性问题. 在Yahoo的Yslow23条规则当中,其中一条是将JS放在底部 .原因是,事实上,大多数浏览器使用单进程处理U ...
- script标签加载顺序(defer & async)
script 拥有的属性 async:可选,表示应该立即下载脚本,但不应妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本.只对外部脚本文件有效. charset:可选.表示通过 src 属性指 ...
- 【转】高性能Javascript--脚本的无阻塞加载策略
原文转自:http://blog.jobbole.com/78191/ Javascript在浏览器中的性能,可以说是前端开发者所要面对的最重要的可用性问题. 在Yahoo的Yslow23条规则当中, ...
- web性能优化之---JavaScript中的无阻塞加载性能优化方案
一.js阻塞特性 JS 有个很无语的阻塞特性,就是当浏览器在执行JS 代码时,不能同时做其他任何事情,无论其代码是内嵌的还是外部的. 即<script>每次出现都会让页面等待脚本的解析和执 ...
- JavaScript无阻塞加载具体方式
将脚本放在底部.\还是放在head中,用以保证在js加载前,能加载出正常显示的页面.\<script>标签放在\前 成组脚本:由于每个\<script>标签下载时阻塞页面解析过 ...
随机推荐
- [原]C#与非托管——动机
Unity3D采用C#作为脚本开发语言,本来是可以直接提供代码局部更新机制的,可惜Mono和Unity3D迫于苹果的压力,在iOS上采用AOT模式运行,断绝了代码局部更新的路(任何一个具有很高知名度的 ...
- Selenium 2.0与Selenum 3.0介绍
什么是Selenium Selenium是一组web自动化测试工具集,它由以下几个部分构成: Selenium IDE(Integrated Development Environment)这是Fir ...
- 浅析Java中synchronized与static synchronized
synchronized关键字 synchronized是进行同步处理而保证线程安全.在一个方法中,如果是方法内的私有变量,那个这个变量是线程安全的,但是类中的实例变量是可能会出现线程安全问题的,当多 ...
- web 项目中a标签传值(中文)到后台的乱码问题
web 项目中a标签传值(中文)到后台的乱码问题 jsp页面中的a标签: .............. <c:forEach items="${sellerList }" v ...
- [转载]转载一篇好文章作为Java与面向对象之随感(3)
关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没法很 ...
- 实现一个竖直的显示表头的表格(vue版本)
今天遇到一个问题,实现这样一个竖直的显示表头的表格,如下图.默认显示两列. vue实现代码如下: tableComponent.vue: <template> <table ...
- MySQL元数据库——information_schema
平时使用MySQL客户端操作数据库的同学,只要稍微留神都会发现,除了我们建的库之外,还经常看到三个数据库的影子: 1. information_schema 2. performance_schema ...
- JavaScript 函数的定义-调用、注意事项
函数定义 函数语句定义 function(a,b){ return a+b; } 表达式定义 var add = function(a,b){return a+b}; //函数表达式可以包含名称,这在 ...
- window下安装mysqldb模块(虚拟环境)
因为在虚拟环境下安装mysql-python走了许多弯路,各种环境问题,特此记录 直接使用pip安装mysql-python会报错 pip install MySQL-python 可以直接选择非虚拟 ...
- Oracle的登陆问题和初级学习增删改查(省略安装和卸载)
1:学习Oracle首先需要安装Oracle,网上已经有很多很多教程了,这里不做叙述,自己百度即可,这里安装的标准版,个人根据需求安装学习或者企业开发即可.如果安装出错,自己百度Oracle的卸载即可 ...