关于非阻塞javascript的真相(The truth about non-blocking JavaScript)
Nicholas C. Zakas的一篇关于非阻塞脚本的文章.
原文:http://calendar.perfplanet.com/2010/the-truth-about-non-blocking-javascript/
很多人都知道有三种技术可以去创建非阻塞的javascript脚本。
1、第一种方法使用<script>标签的defer属性。
浏览器读取<script>标签时立即下载javascript文件,但是不会去执行具体的javascript语言。下载的过程是不会阻塞页面上其他的资源的。被延迟的脚本真正的执行是在页面DOMContentLoade事件之前执行,并且按照脚本出现在文档里的先后顺兴执行。defer属性被ie4,firefox3.,safari5,chrom7所支持。
<script type="text/javascript" defer src="foo.js"></script>
2、第二种方法是使用<script>标签HTML5支持的async属性。
<script type="text/javascript" async src="foo.js"></script>
异步的脚本与defer属性相同都是立即下载无阻塞的js文件,不同的是async属性的脚本在下载完后立即执行,也就是页面仍然在下载的过程中已经开始执行此脚本。存在问题的是异步脚本的执行顺序是不能明确的。唯一能确定的是异步脚本是在load事件之前执行。
3、第三种方式是目前最被经常用到也很流行,使用js去动态创建<script>标签。
var script = document.createElement("script"); script.type = "text/javascript"; script.src = "foo.js"; document.getElementsByTagName("head")[0].appendChild(script);
当脚本无阻塞的下载完js文件时,立即执行脚本语言。firefox<4跟opera浏览器执行动态脚本的顺序是按照动态插入的顺序,而其他浏览器的执行顺序确是不明确的。
很多人知道这三种非阻塞的方法确实能够不影响页面的渲染及资源的下载,但是很少人知道这些却阻塞load事件。这意味着在页面资源加载期间,使用以上非阻塞技术将延迟执行window.onload事件,直到所有的脚本都已经执行完后才会开始执行window.onload事件。一般人们都希望window.onload在页面初始完后尽可能快的被执行,因此可以使用setTimeout来解决这个问题,如下:
//doesn't block the load event setTimeout(function(){ var script = document.createElement("script"); script.type = "text/javascript"; script.src = "foo.js"; document.getElementsByTagName("head")[0].appendChild(script); }, 0);
使用0ms的计时器后可以确保不会阻塞window.onload事件,但是却不能确保计时器的执行是在onload事件之前或是之后。因此如果你想确保在onload之后执行可以使用:
//doesn't block the load event window.onload = function(){ var script = document.createElement("script"); script.type = "text/javascript"; script.src = "foo.js"; document.getElementsByTagName("head")[0].appendChild(script); };
因此在加载非阻塞脚本的时候你应该去考虑一下是否阻塞了load事件和你的window.onload事件。因此增加一个计时器就会万无一失。