网站优化之异步加载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 async and defer attributes are boolean attributes that indicate how the script should be
executed. The defer and async attributes must not be specified if the src attribute
is not presThere are three possible modes that can be selected using these attributes.
If the async attribute is present, then the script will be executed asynchronously,
as soon as it is available. If the async attribute is not present but the defer attribute 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 for script start and end tags in HTML, in foreign content, and in XML,
the rules for the document.write() method, the handling of scripting, etc.

The defer attribute may be specified even if the async attribute is specified,
to cause legacy Web browsers that only support defer (and not async) to fall
back to the defer behavior instead of the synchronous blocking behavior that is the default.

Changing the src, type, charset, async, and defer attributes 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: , , , , , ,

Post a Comment


最热门文章

常用标签

云输入法 好的站点 数据之美 数据库优化 网站优化 网页安全 跨浏览器 输入法 重构 页面优化 Android CSS css优化 facebook firebug HTML html重构 html5 HTTP协议 http历史 ie javascript Last Modified lighttpd linux linux后台开发 MYSQL mysql优化 netstat ping QQ QQ云输入法 QQWeb输入法 web web开发 Web服务器 web服务器配置 web设计 WEB颜色 xhtml