现在的位置: 首页 > 综合 > 正文

js脚本加载总结

2013年02月18日 ⁄ 综合 ⁄ 共 6867字 ⁄ 字号 评论关闭

原文链接:http://www.cnblogs.com/zhuimengdeyuanyuan/archive/2013/04/26/3043675.html

这段时间工作工作上不是很紧,零星的在研究浏览器的一些东西,刚好这个月又一次轮到我做沙龙讲座了,想好了好久,就来一次js脚本加载的总结吧!这一块应该对于很多做项目的朋友来会有所帮助吧!

  1、js起源

  总所周知网页最开始的形态是静态的(也就是所谓的静态网页),那时候的网页主要用于浏览资料信息,可是随着用户需求的增加,用户希望在页面上做一些交互操作,比如页面需要验证才能访问、页面输入的一些数据希望下次还可以访问等等,js的出现满足了人们的需求。也就出现了所谓的动态网页。

  虽然js给人们带来了很好的交互性,但是起初人们乱用脚本,只是网页页面代码混乱不堪,当css的出现解决了这一问题:

  

  知道如今,我们的网页也是分为三部分:HTML(主要放置界面元素)、CSS(主要负责界面布局)和JS(主要负责界面交互)。

  大家都知道这三部分,但是有很多人不注意一些细节,导致做出的网页访问时效率低下。在这里我将和大家讨论一下关于js的一些知识,希望给大家带来一定帮助吧!

  2、三种使用脚本方式

  2.1内部引用JavaScript

  2.11通过HTMLscript标签加载JavaScript代码

  如:  

复制代码
<head>
    <script type="text/javascript">
        document.write("Hello World !");
    </script>
</head>
复制代码

  2.12通过注释隐藏JavaScript代码

  如:

复制代码
<head>
    <script type="text/javascript">
        <!--
        document.write("Hello World !");
        //-->
    </script>
</head>
复制代码

  <!-- ... //-->当浏览器不支持JavaScript时,屏蔽JavaScript代码。这个代码是骇客技术,<!-- ... -->于HTML注释,// 是JavaScript注释。当浏览器支持JavaScript时//代码生效,因此HTML的注释没有效果;当浏览器不支JavaScript时,//代码无效,因此屏蔽了<!--
... -->之间的JavaScript代码。现在这种隐藏JavaScript代码的方式可以忽略,因为没有浏览器不支持JavaScript,除了部分用户手动禁止浏览器的JavaScript功能,但是这种情况很少发生。

  2.1.3使用noscript标签为用户提供更好的体验

  如:  

复制代码
<body>
    <script type="text/javascript">
        document.write("Hello World !");
    </script>
    <noscript>
        <p>如果您想查看此网页,则必须启用JavaScript。
              然而,JavaScript 似乎被禁用,要么就是您的
              浏览器不支持 JavaScript。请更改您的浏览器
              选项以启用 JavaScript,然后刷新。
        </p>
    </noscript>
</body>
复制代码

  通过JavaScript注释的方式可以隐藏JavaScript代码,通过noscript标签可以为用户提供更好的体验(提示用户你的浏览器不支持JavaScript)。

  2.2外部引用JavaScript

  使用<script>标签的src属性来加载js脚本。通常JavaScript文件可以使用script标签加载到网页的任何一个地方,但是标准的方式是加载在head标签内。为防止网页加载缓慢,也可以把非关键的JavaScript放到网页底部。 

复制代码
<script type="text/javascript" src=“SuperMap.js"></script>
复制代码

  这里有几点好处:

  1)避免使用<!-- ... //-->,骇客技术。

  2)统一定义JavaScript代码,方便查看,方便维护。

  3)使代码更安全,可以压缩,加密单个JavaScript文件。

  4)浏览器可以缓存JavaScript文件,减少宽带使用。

  2.3内联引用JavaScript

  内联引用是通过HTML标签中的事件属性实现的。

复制代码
<input type="button" value="点我" onclick="alert('你点击了一个按钮');">
复制代码

  上面示例将调用input标签的onclick属性,弹出一个提示框。

  3内外脚本的比较

  内联脚本方式使用场景很少,几乎没什么优势。

  内部脚本示例:http://stevesouders.com/hpws/inlined.php

  外部脚本示例:http://stevesouders.com/hpws/external.php

  内部脚本示例只有一个HTML文档,其大小为87kb,所有的js和css都包含在HTML文档自身中。外部脚本示例包含一个HTML文档(7kb)、一个样式表(59kb)和三个脚本(1kb、11kb和9kb),总计87kb。尽管所需下载的总数据量是相同的,内部脚本示例还是比外部示例快30%到50%。这主要是因为外部示例需要承担多个HTTP请求带来的开销。尽管外部脚本示例可以从样式表和脚本的并行下载中获益,但一个HTTP请求与五个HTTP请求之间的差距导致内部脚本示例更快一些。

  尽管结果如此,现实中还是使用外部文件会更合理一些,因为外部文件所带来的收益--------js文件有机会被浏览器缓存起来。HTML文档--------至少是那些包含动态内容的HTML文档--------通常不会被配置为可以进行缓存。当遇到这种情况时(HTML没有被缓存),每次请求HTML文档都要下载内部的js。另一方面,如果js是外部文件,浏览器就能缓存它们,HTML文档的大小减小,而且不会增加HTTP请求的数量。

   关键因素是,与HTML文档请求数量相关的、外部js组件被缓存的频率。这个因素尽管难以量化,但可以通过下面的手段进行衡量:

  3.1页面查看

  每个用户产生的页面查看越少,内部js的论据越强势。想象一个普通用户每个月只访问你的网站一次。在每次访问之间,外部js文件很可能从浏览器的缓存中移除。另一方面,如果普通用户能够产生很多的页面查看,浏览器很可能将外部Js文件放在缓存中。使用外部文件提供js带来的收益会随着用户每月的页面查看次数或用户每会话产生的页面查看次数的增长而增加。

  3.2空缓存VS完整缓存

  在比较内部和外部文件时,知道用户缓存外部组件的可能性这一点非常重要。我们在Yahoo!进行了测量,发现每天至少携带完整缓存访问Yahoo!功能一次的用户占40%到60%。同样的研究表明,具有完整缓存额的页面查看数量占75%到85%。注意第一个统计测量的是“唯一用户”而第二个是“页面查看”。具有完整缓存的页面查看所占的百分比比携带完整缓存的唯一用户的百分比高,这是因为很多用户在一次会话中进行了多次页面查看。每天,用户可能只有开始的一次访问携带的是空缓存,之后的多次后续页面查看都具有完整缓存。如果你的网站的本质上能够为用户带来高完整缓存率,使用外部文件的收益就更大。如果不太可能产生完整缓存,则内部脚本是更好的选择。

  3.3组件重用

  如果你的网站中的每个页面都使用了相同的js,使用外部文件可以提高这些组件的重用率。在这种情况下使用外部文件更加具有优势,因为当用户在页面间导航时,js组件已经位于浏览器的缓存中了。相反的情况也很容易理解--------如果没有任何两个页面共享相同的js,重用率就会非常低。难的是绝大多数网站不是非黑即白的。这就带来一个单独相关的问题--------当把js打包到外部文件中时,应该把边界划在哪里?

  

  在典型情况下,页面之间的js的重用即不可能100%重叠,也不可能100%无关。在这种中间情形中,一个极端就是为每个页面提供一组分离的外部文件。这种方式的缺点在于,每个页面都强制用户使用另外一组外部组件并产生令响应时间变慢的HTTP请求。这种方式对于普通用户只访问一个页面和很少进行跨页访问的网站来说是有意义的。

  另一个极端是创建一个单独的、联合了所有js的文件。这只要求用户生成一个HTTP请求,但它增加了用户首次进行页面查看时的下载数据量。在这种情况下,用户浏览页面时要下载的js多于所需的数量。而且,在任何一块独立的脚本改变后,都需要更新这个文件,使所有用户已经缓存了的当前版本无效。这种情况对于那些每月会话数量较高、普通用户在一个会话中访问多个不同页面的网站来说是有意义的。

  如果你的网站不符合这两种极端情况,最好的答案就是折中。将你的页面划分成几种页面类型,然后为每种类型创建单独的脚本,这比维护一个单独的文件要复杂,但通常比为每个页面维护不同的脚本要容易,并且对于给定的任意页面都只需要下载很少的多余的js。

  最后你做出的与js外部文件的边界相关的决定影响着组件的重用程度。如果你可以找到一个平衡点,实现较高的重用性,那么外部文件的论据更强势一些。如果重用度很低,还是内部脚本更有意义些。

  在对于内部和外部脚本进行比较分析时,关键点在于与HTML文档请求数量相关的外部js组件被缓存的频率。在此我介绍了三种基准(页面查看、空缓存VS完整缓存和组件重用),这有助于你确定最好的选择。对于任何网站来说,正确答案都依赖于这些基准。

  大家如果还想更详细的了解浏览器脚本、css等的一些效率问题,可以看《高性能网站建设指南》,那里面的14条具体的优化原则的确很精辟。

  4 将脚本放在底部

  4.1脚本带来的问题

  下面是一个脚本放在中部的示例

  http://stevesouders.com/hpws/js-middle.php

  经过编程的脚本下载需要很长时间,因此很容易看到问题--------页面的下半部分要花很长时间才能显示。出现这一现象是因为脚本阻塞了并行下载。在回顾了浏览器如何并行下载之后,我们再回过头解决这一问题。

  4.2并行下载

  对响应时间影响最大的是页面中组件的数量。当缓存为空,每个组件都会产生一个HTTP请求,有时即便缓存是完整的亦是如此。要知道浏览器会并行地执行HTTP请求,你可能会问,为什么HTTP请求的数量会影响响应时间呢?浏览器不能一次将它们都下载下来吗?

  对此的解释要回到HTTP 1.1规范,该规范建议浏览器从每个主机名并行下载两个组件。很多web页面需要从一个主机名下载所有的组件。查看这些HTTP请求会发现它们是呈阶梯状的,如图所示:

  

                      图4.1

 如果一个Web页面平均地将其组件分别放在两个主机名下,整体响应时间将可以减少大约一半。HTTP请求的行为看起来会是图4.2所示

  

                        图4.2

  此处可以并行下载四个组件(每个主机名两个)。为了对页面加载变快的现象给出可视的效果,其中每个时间块的横向宽度和图4.1是一样的。

  每个主机名并行下载两个组件的限制只是一个建议。默认情况下浏览器都遵守这一建议,但用户也可以重写该默认设置。但增加并行下载数量并不是没有开销的,其优劣取决于你的宽带和CPU速度。

  4.3脚本阻塞下载

  并行下载组件的优点是很明显的。然而,在一些比较旧的浏览器在下载脚本时并行下载实际上是被禁用的--------即使使用了不同的主机名,浏览器也不会启动其他的下载。其中一个原因是,脚本可能使用document.write来修饰页面内容,因此浏览器会等待,以确保页面能够恰当的布局。(现在的浏览器虽然可以并行下载,但是同样阻塞布局)在下载脚本时浏览器阻塞并行下载的另一个原因是为了保证脚本能够按照正确的顺序执行。如果并行下载多个脚本,就无法保证响应是按照特定顺序到达浏览器的。例如:后面的脚本比页面中之前出现的脚本更小,它可能首先执行。如果它们之间存在着依赖关系,不按照顺序执行就会导致js错误。

  如下是一个例子:

  http://stevesouders.com/hpws/js-blocking.php

  该页面按照顺序包含下列组件

    1、来至host1的一个图片

    2、来至host2的一个图片

    3、来至host1的一个加载需要大约10秒的脚本

    4、来至host1的一个图片

    5、来至host2的一个图片

  4.4最差情况:将脚本放在顶部

  至此,脚本对Web页面的影响就清楚了:

    1、脚本会阻塞对其后面内容的呈现

    2、脚本会阻塞对其后面组件的下载

  如果将脚本放在页面顶部--------正如通常情况那样--------页面中的所有东西都位于脚本之后,整个页面的呈现和下载都会被阻塞,直到脚本加载完毕脚本放在顶部的示例:

  http://stevesouders.com/hpws/js-top.php

  由于整个页面的呈现被阻塞,因此导致了白屏现象。逐步呈现对于良好的用户体验来说是非常重要的,但缓慢的脚本下载延迟了用户所期待的反馈。

  4.5最佳情况:将脚本放在底部

  放置脚本的最好地方时页面的底部。这不会阻止页面内容的呈现,而且页面中的可是组件可以尽早下载。脚本放在底部的示例:

  http://stevesouders.com/hpws/js-bottom.php

  把两个页面--------脚本放在顶部的和脚本放在底部的--------并列放在一起浏览,其对比更为突出。可以在下面这个示例中看到这一点:

  http://stevesouders.com/hpws/move-scripts.php

  4.6正确地放置

  前面那些示例是使用了大概需要10秒才能下载完的脚本。希望你使用的脚本不需要这么长时间的延迟,但一个脚本很可能花费比预期长的时间,用户的宽带也会影响脚本的响应时间。你的页面中的脚本所产生的影响可能没有这里展示的那么严重,但仍需要注意。在页面中包含多个脚本也会带来问题。

  在很多情况下,很难将脚本移到底部。例如,如果脚本使用document.write向页面中插入了内容,就不能将其移动到页面中靠后的位置。

  经常出现的另外一种建议是使用延迟脚本。Defer属性表明脚本不包含document.write,浏览器得到这一线索就可继续进行呈现。从下面的示例可以看到这一点:

  http://stevesouders.com/hpws/js-defer.php

  但是不保险,有一些老的浏览器不能识别defer,所以最好还是将脚本放于底部。

 5动态加载脚本

  详见我之前的博客

js动态加载脚本

  6三种实用方式

  6.1异步批量添加外部脚本

  很多时候我们由于产品模块的划分,一个页面可能需要加载几个脚本,我们需要考虑两点:1、脚本之间是否有依赖关系,如果存在依赖关系即使我们使用script标签是按照顺序的,但是并行下载是一起下载的,如果出现后面的包先下载完,那么执行脚本时就可能出现错误;2、考虑到效率,一般情况下异步加载比同步加载会快一些。为了解决如上问题,我们可以利用之前讨论的知识进行组合

复制代码
<html>
<head>
<title></title>
<script type="text/javascript">
function init()
{
//这里第一个参数是一个数组,可以任意多个,加载顺序按照数组的顺序进行保证
//第二个参数是回调函数,当所有包都确认加载完毕后需要执行的脚本
//第三个参数是script的标签,这个参数可以省略,没有实质意义
attachScript(["http://www.cnblogs.com/5/loadJS.js","http://www.cnblogs.com/5/package.js"],operation,"yy")();
}
function operation()
{
//可以运行,显示“成功加载”
functionOne();
}
//异步批量加载脚本,并且根据数组urlArray中的url顺序来加载
function attachScript(urlArray, callback, id) {
if(urlArray && ((typeof urlArray) == "object"))
{
if(urlArray.constructor == Array)
{
if(urlArray.length>1)
{
var array = urlArray.splice(0,1);
return function(){
var dataScript = document.createElement('script');
dataScript.type
= 'text/javascript';

抱歉!评论已关闭.