网站优化之异步加载javascript--by{流芒}-{土豆}
在我们的页面中,如果不是显示指出来的话,javascript是同步加载的,也就是javascript的加载是阻塞的,后面的元素需要等待javascript加载完毕后才能进行再加载。呵呵,对于一些意义不是很大的javascript,如果放在页面的头部,如果加载很慢的话,会严重影响用户的体验的。
有人会问这时为什么呢?因为有可能你的javascript代码会动态的植入一些元素到页面的dom中。
因此对于那些会有修改dom的javascript(最简单如里面会有document.writlen这样的语句),我们只能阻塞的加载,而且最好也是放在页面的最底部。但是对于那些不会导致dom修改的javascript,如一些统计的javascript,如google的统计等,我们完全可以异步的来加载,不必同步阻塞的来等待。如何异步加载一个javascript文件呢?
一 defer方式
在w3c的html中定义的script标签有一个defer的属性,这个属性开启的话表示这段javascript代码可以延迟加载。
<!ELEMENT SCRIPT - - %Script; -- script statements --> <!ATTLIST SCRIPT charset %Charset; #IMPLIED -- char encoding of linked resource -- type %ContentType; #REQUIRED -- content type of script language -- src %URI; #IMPLIED -- URI for an external script -- defer (defer) #IMPLIED -- UA may defer execution of script -- >
- defer [CI]
- When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no “document.write” in javascript) and thus, the user agent can continue parsing and rendering.
二 对于html5中的async和defer方式interface HTMLScriptElement : HTMLElement { attribute DOMString src; attribute boolean async; attribute boolean defer; attribute DOMString type; attribute DOMString charset; attribute DOMString text; };The
asyncanddeferattributes are boolean attributes that indicate how the script should be
executed. Thedeferandasyncattributes must not be specified if thesrcattribute
is not presThere are three possible modes that can be selected using these attributes.
If theasyncattribute is present, then the script will be executed asynchronously,
as soon as it is available. If theasyncattribute is not present but thedeferattribute is
present, then the script is executed when the page has finished parsing. If neither attribute
is present, then the script is fetched and executed immediately, before the user agent continues
parsing the page.The exact processing details for these attributes are, for mostly historical reasons,
somewhat non-trivial, involving a number of aspects of HTML. The implementation requirements
are therefore by necessity scattered throughout the specification.
The algorithms below (in this section) describe the core of this processing,
but these algorithms reference and are referenced by the
parsing rules forscriptstart and end tags in HTML, in foreign content, and in XML,
the rules for thedocument.write()method, the handling of scripting, etc.The
deferattribute may be specified even if theasyncattribute is specified,
to cause legacy Web browsers that only supportdefer(and notasync) to fall
back to thedeferbehavior instead of the synchronous blocking behavior that is the default.Changing the
src,type,charset,async, anddeferattributes dynamically has no
direct effect; these attribute are only used at specific times described below.
如下一段代码进行测试:
<html>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=gb2312″>
<script src=”defer.js” defer=”true”></script>
<script src=”nodefer.js”></script>
<script>
alert(“test”);
</script>
</head>
<body>
defer async test
</body>
</html>
defer.js
alert(“i am defer”);
nodefer.js
alert(“I am not defer”);
出现的结果是:
I am not defer
test
i am defer
修改defer为async尝试一下,请用ie7或者firefox测试,我用的chrome 4暂不支持。
ie7支持defer,firefox支持defer以及aysnc,chrome 4两个不都不支持。
延迟加载在实际中有什么用途呢?
我们来看看google的统计代码的js是如何来添加的:
var ga = document.createElement('script');
ga.type = 'text/javascript'; ga.async = true; //对于支持html5的浏览器,这是很有用的。
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') +
'.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
google的统计代码需要兼容各种页面,如https、以及一些没有head标签的页面等。来看看目前的QQ云输入法是怎么样来插入javascript代码的呢?
function(q){!!q?q.toggle():(function(d,j){j=d.createElement(‘script’);j.src=’http://ime.qq.com/fcgi-bin/getjs’;j.setAttribute(‘ime-cfg’,'lt=2′);d.getElementsByTagName(‘head’)[0].appendChild(j)})(document)})(window.QQWebIME)
呵呵,这段代码在没有head标签的页面上就是无法使用的了,google的代码都是需要身经百战的,因此,平时的过程中学学google也是一种不错的选择。
再来看看jquery动态加载的代码片段,很是简洁和漂亮,同时需要注意appendChild在ie下的bug问题,还是使用insertBefore的好:
head = document.getElementsByTagName ("head")[0] ||
document.documentElement;
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709 and #4378).
head.insertBefore(script, head.firstChild);
参考:
http://code.google.com/intl/zh-CN/apis/analytics/docs/tracking/asyncTracking.html
http://dev.w3.org/html5/spec/Overview.html#script
Tags: javascript, javascript优化, QQ, QQ云输入法, 延迟加载, 异步加载, 网站优化