阅读更多

23顶
3踩

Web前端

转载新闻 JavaScript 装载和执行

2013-06-05 11:02 by 副主编 WnouM 评论(8) 有10555人浏览


本文转载自酷壳网原文内容如下:

一两个月前在淘宝内网里看到一个优化Javascript代码的竞赛,发现有不少的人对Javascript的执行和装载的基础并不懂,所以,从那天起我就想写一篇文章,但一直耽搁了。自上篇《浏览器渲染原理简介》,正好也可以承前启后。

首先,我想说一下Javascript的装载和执行。通常来说,浏览器对于Javascript的运行有两大特性:

  1. 载入后马上执行
  2. 执行时会阻塞页面后续的内容(包括页面的渲染、其它资源的下载)。
于是,如果有多个js文件被引入,那么对于浏览器来说,这些js文件被被串行地载入,并依次执行。

因为javascript可能会来操作HTML文档的DOM树,所以,浏览器一般都不会像并行下载css文件并行下载js文件,因为这是js文件的特殊性造成的。所以,如果你的javascript想操作后面的DOM元素,基本上来说,浏览器都会报错说对象找不到。因为Javascript执行时,后面的HTML被阻塞住了,DOM树时还没有后面的DOM结点。所以程序也就报错了。

传统的方式

所以,当你写在代码中写下如下的代码:

<script type="text/javascript" src="http://coolshell.cn/asyncjs/alert.js"></script>


基本上来说,head里的 <script>标签会阻塞后续资源的载入以及整个页面的生成。我专门做了一个示例你可以看看:示例一。 注意:我的alert.js中只有一句话:alert(“hello world”) ,这更容易让你看到javascript是自知阻塞的。所以,你知道为什么有很多网站把javascript放在网页的最后面了。因为,绝大多数的Javascript代码并不需要等。

document.write方式

于是,你可能以为document.write()这种方式能够解决不阻塞的方式。你当然会觉得,document.write了<script>标签后就可以执行后面的东西去了,这没错,对于在同一个script标签里的Javascript的代码来说,是这样的,但是对于整个页面来说,这个还是会阻塞。 下面是一段测试代码:

<script type="text/javascript" language="javascript">
    function loadjs(script_filename) {
        document.write('<' + 'script language="javascript" type="text/javascript"');
        document.write(' src="' + script_filename + '">');
        document.write('<'+'/script'+'>');
        alert("loadjs() exit...");
    }
 
    var script = 'http://coolshell.cn/asyncjs/alert.js';
 
    loadjs(script);
    alert("loadjs() finished!");
</script>
 
<script type="text/javascript" language="javascript">
   alert("another block");
</script>


你觉得alert的顺序是什么?这里的想关的测试页面:示例二

script的defer和async属性

IE自从IE6就支持defer标签,如:

<script defer type="text/javascript" src="./alert.js" >
</script>


对于IE来说,这个标签会让IE并行下载js文件,并且把其执行hold到了整个DOM装载完毕(DOMContentLoaded),多个defer的<script>在执行时也会按照其出现的顺序来运行。最重要的是<script>被加上defer后,其不会阻塞后续DOM的的渲染。但是因为这个defer只是IE专用,所以一般用得比较少。

而我们的HTML5也加入了一个异步载入javascript的属性:async,无论你对它赋什么样的值,只要它出现,它就开始异步加载js文件。但是, async的异步加载会有一个比较严重的问题,那就是它踏实地践行着:载入后马上执行这条军规,所以,虽然它并不阻塞页面的渲染,但是你也无法控制他执行的次序和时机。你可以看看这个示例去感受一下

支持 async标签的浏览器是:Firefox3.6+,Chrome 8.0+,Safari 5.0+,IE 10+,Opera还不支持(来自这里)所以这个方法也不是太好。因为并不是所有的浏览器你都能行。

动态创建DOM方式

这种方式可能是用得最多的了。

function loadjs(script_filename) {
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', script_filename);
    script.setAttribute('id', 'coolshell_script_id');
 
    script_id = document.getElementById('coolshell_script_id');
    if(script_id){
        document.getElementsByTagName('head')[0].removeChild(script_id);
    }
    document.getElementsByTagName('head')[0].appendChild(script);
}
 
var script = 'http://coolshell.cn/asyncjs/alert.js';
loadjs(script);


这个方式几乎成了标准的异步载入js文件的方式,这个方式的演示请参看:示例三。这方式还被玩出了JSONP的东东,也就是我可以为script的src指定个后在台的脚本(如PHP),而这个PHP返回一个javascript函数,其参数是一个json的字符串,返回来调用我们的javascript的参数。你可以看一下这个示例:t.js (这个示例是我之前在微博征集的一个异步ajax调用的小例子

按需异步载入js

上面那个DOM方式的例子解决了异步载入Javascript的问题,但是没有解决我们想让他按我们指定的时机运行的问题。所以,我们只需要把上面那个DOM方式绑到某个事件上来就可以了。比如:

绑在window.load事件上——示例四

你一定要比较一下示例四和示例三在执行上有什么不同,我在这两个示例中都专门用了个代码高亮的javascript,看看那个代码高亮的的脚本的执行和我的alert.js的执行的情况,你就知道不同了)

window.load = loadjs("http://coolshell.cn/asyncjs/alert.js")


绑在特定的事件上——示例五

<p style="cursor: pointer" onclick="LoadJS()">Click to load alert.js </p>


这个示例很简单了。当你点击某个DOM元素,才会真正载入我们的alert.js。

更多

但是,绑定在事件上这个事似乎又过了一点,因为只有在点击的时候才会去真正的下载。这会太慢了了。好了,到这里,要抛出我们的终极问题——我们想要异步地把js文件下载到用户的本地,但是不执行,仅当在我们想要执行的时候去执行。

要是我们有下面这样的试就好了:

var script = document.createElement("script");
script.noexecute = true;
script.src = "alert.js";
document.body.appendChild(script);
 
//后面我们可以这么干
script.execute();


可惜的是,这只是一个美丽的梦想,今天我们的Javascript还比较原始,这个JS梦还没有实现呢。

所以,我们的程序员只能使用hack的方式来搞。

有的程序员使用了非标准的script的type来cache javascript。如:

<script type=cache/script src="./alert.js"></script>


因为”cache/script”,这个东西根本就不能被浏览器解析,所以浏览器也就不执能把alert.js当javascript去执行,但是他又要去下载js文件,所以就可以搞定了。可惜的是,webkit严格符从了HTML的标准——对于这种不认识的东西,直接删除,什么也不干。于是,我们的梦又破了。

所以,我们需要再hack一下,就像N多年前玩preload图片那样,我们可以动用object标签,于是我们有下面这样的代码:

function cachejs(script_filename){
    var cache = document.createElement('object');
    cache.data = script_filename;
    cache.id = "coolshell_script_cache_id";
    cache.width = 0;
    cache.height = 0;
    document.body.appendChild(cache);
}


然后,我们在的最后调用一下这个函数。请参看一下相关的示例:示例六

在Chrome下按 Ctrl+Shift+I,切换到network页,你就可以看到下载了alert.js但是没有执行,然后我们再用示例五的方式,因为浏览器端有缓存了,不会再多服务器上下载alert.js了。所以,就能保证执行速度了。

关于这种preload你应该不会陌生了。你还可以使用Ajax的方式,如:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'new.js');
xhr.send('');


我这里不就再多说了。好了,这是所有的内容了,希望大家看过后能对Javascript的载入和执行,以及相关的技术有个了解。同时,也希望各前端高手不吝 赐教!
  • 大小: 129.7 KB
来自: 酷壳
23
3
评论 共 8 条 请登录后发表评论
8 楼 leon1509 2013-06-08 09:01
写得真不错,就是有些地方语句不通顺!
7 楼 leaow567 2013-06-07 09:49
好文,受教了
6 楼 lnaigg 2013-06-07 00:20
xhr+eval还有个问题是无法跨域
5 楼 lnaigg 2013-06-07 00:19
看了半天,示例六不是异步装载、异步执行啊
cachejs函数只是让浏览器记录一下有这么个脚本,其实是没有下载下来的
loadjs函数才是真正下载脚本。
而且起到缓存作用的是loadjs里面的script标签,跟cachejs里面创建的对象没虾米关系

我的需求是,先异步下载下来,我想执行的时候就执行。
xhr+eval,是可以做到预加载和缓存脚本的。
xhr+eval的问题是,当我想同时load多个脚本文件时,要不低效地串行加载js,要不并行加载js就无法控制先后执行顺序。
4 楼 nomandia 2013-06-06 17:16
如果想阻止异步装在的JS运行可以这么干:
var script = document.createElement('script');
script.defer=true; //注意这个属性
script.src=target_url;

即,script标记的defer属性默认是false的也就是不阻止脚本在装在完毕后运行,把他给禁止了就完了。

其他的倒是没什么,不过基本上不用document.write。
3 楼 天朗java 2013-06-06 09:45
怎么还有人点踩,应该是高人吧,能给点分享不?
2 楼 三里小龙 2013-06-05 12:53
类似缓存的做法的确很值得借鉴,这样基本上达到我们人为去控制脚本的触发,这一点提供了很好的思路,也比较新颖,谢啦!
1 楼 kevinwqw 2013-06-05 12:02
好文,受教了

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 计算机思科配置个人总结,有关思科模拟器实训总结范文

    有关思科模拟器实训总结范文篇一:Cisco路由模拟器实验总汇实验一:1. 口令和设备名设置添加任意的交换机或路由器,先对...进入全局配置模式switch(config)#hostname swa ;设置交换机名swa(config)#enable secret ...

  • 黑马点评项目全部功能实现及详细笔记--Redis练手项目

    黑马点评项目实战篇全部业务实现以及部分代码逻辑分析与记录

  • LVS的DR模式(ldirectord的使用,keepalived配置高可用集群)

    vim /etc/yum.repos.d/rhel-source.repo 添加如下几行 [rhel-source] name=Red Hat Enterprise Linux $releasever - $basearch - Source baseurl=http://172.25.65.250/rhel6.5 enabled=1 gpgcheck=0 [High...

  • 二分类器的常用评价指标

    虽说评价指标之间却有全面和局部、对数据不平衡敏感和不敏感之别,但是希望诸位读者和我自己都不要孤立和教条地看待和选择指标,不同的业务场景、不同的目的有不同的要求,运用智慧和经验灵活运用才是我们所追求的...

  • jboss怎么配置支持php,Eclipse+JBoss+MySQL开发环境设置全攻略_php

    作为开发环境,如果采用经典配置:JBuilder+weblogic+oracle,自是得心应手,但价格是惊人的。此配置主要是针对大型或超大型应用,硬件要求也很高,针对国内以中小型应用为主的现况,不作推荐。虽然国内开发者早已...

  • NDSL

    很好,请各位继续往下看。2008年idsl和NDSL的价格稳定在1100左右. 【为何选择NDSL?】 有这种疑问的朋友大多数是没有看到NDSL实机的,倘若真正是看到了NDSL实机,只要你是任天堂爱好者,砸锅卖铁...

  • 水清则无鱼--走出软件作坊:三五个人十来条枪 如何成为开发正规军(八)

    那天,突然给我打了电话,说要请我吃饭。 饭肯定是不能白吃的。朋友告诉我:唉,烦心啊。客户不成熟,是麻烦事。客户太成熟,也是个麻烦事。 我说,此话怎讲? 我朋友说:你看,我过去跟单,客户对软件不懂...

  • 转:水清则无鱼--走出软件作坊:三五个人十来条枪 如何成为开发正规军(八)...

    那天,突然给我打了电话,说要请我吃饭。 饭肯定是不能白吃的。朋友告诉我:唉,烦心啊。客户不成熟,是麻烦事。客户太成熟,也是个麻烦事。 我说,此话怎讲? 我朋友说:你看,我过...

  • 三五个人十来条枪 如何成为开发正规军(八)

    那天,突然给我打了电话,说要请我吃饭。 饭肯定是不能白吃的。朋友告诉我:唉,烦心啊。客户不成熟,是麻烦事。客户太成熟,也是个麻烦事。 我说,此话怎讲? 我朋友说:你看,我过去跟单,客户对软件...

  • 玩转MySQL:一站式解决分库分表后患问题方案

    当然,保障分布式系统下ID唯一性的解决方案很多,如下: ①通过设置数据库自增机制的起始值和步长,来控制不同节点的ID交叉增长,保证唯一性。 ②在业务系统中,利用特殊算法生成有序的分布式ID,比如雪花算法、...

  • Redis学习笔记①基础篇_Redis快速入门

    配置完成之后就可以启动 redis 了(此时是按照配置文件来运行的) redis-server /usr/local/src/redis-6.2.6/redis.conf 可以使用如下命令查看 redis 服务是否正常运行 ps -ef | grep redis 关闭 redis 服务的话,...

  • 九月十月百度人搜,阿里巴巴,腾讯华为小米搜狗笔试面试八十题

    ,你可以把你的答案或代码直接评论在本文之下,也可以通过私信或邮件发给我,感谢诸位。同时,以下所有任何题目所给的点评里的答案,尤其是所给的外部链接若有任何问题,欢迎在本文评论下留言指正,谢谢。 答题除了...

  • 使用循环神经网络(RNN)实现影评情感分类

    七、对模型进行配置 模型的配置参数大多数都被提取出来,单独放到了settings.py文件中,可以在这里对模型进行配置。 八、运行模型 至此,模型构建完成。模型的运行步骤大致如下: 1.确保数据文件放在了对应路径中,...

  • 关于使用Spring导致c3p0数据库死锁问题

    只要你用Spring控制事务,写了如下的事务控制配置: id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"&gt;   ref="transactionManager"/&gt; ...

  • 学习笔记:SpringCloud 微服务技术栈_实用篇①_基础知识

    若文章内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系博主删除。 前言 学习视频链接 SpringCloud + RabbitMQ + Docker + Redis + 搜索 + 分布式,史上最全面的 SpringCloud 微服务...

  • 《CSS样式表行为手册》中文chm最新版本

    CSS样式表里重点讲述“行为”功能的一本CHM参考手册,很实用方便,内容也很丰富,收藏一下哦!

  • 1-中国各地区-固定资产投资-房地产开发投资情况(1999-2020年)-社科数据.zip

    中国各地区固定资产投资中的房地产开发投资数据集涵盖了1999至2020年的详细统计信息。该数据集包含了全国各城市地级市州的房地产开发投资情况,这些数据对于理解中国城市化进程、经济发展和房地产市场趋势至关重要。数据集中的指标包括年份、地区以及对应的房地产开发投资额(以亿元为单位),这些数据来源于中国区域统计年鉴及各省市统计年鉴。通过这些数据,研究者和决策者可以深入了解不同地区的经济动态,评估房地产市场的健康状况,并据此制定相应的政策和战略。这些数据不仅有助于宏观经济分析,还能为房地产开发商提供市场进入和扩张的决策支持。

  • 1-中国各地区数字经济发展对环境污染的影响数据(2011-2021年)-社科数据.zip

    中国各地区数字经济发展对环境污染的影响数据集(2011-2021年)提供了深入分析数字经济与环境污染关系的实证数据。该数据集涵盖了中国各地区在数字经济发展水平、环境污染物排放量、人口与经济指标、外资利用情况以及绿色专利指标等多个维度的数据。具体来说,数据集包括了行政区划代码、年份、所属省份等基本信息,以及数字经济水平熵值法、PM2.5均值、工业烟粉尘排放量、工业二氧化硫排放量、工业废水排放量等关键指标。此外,数据集还涉及了人口密度、人均地区生产总值、实际利用外资额占GDP之比、科学支出占比等经济和人口统计数据,以及绿色专利申请和授权总量等创新指标。这些数据不仅有助于研究者探讨数字经济对环境污染的直接影响,还能分析其潜在的中介机制和影响因素,为理解数字经济如何影响环境质量提供了宝贵的数据资源。

  • 1-中国各区县-工业行业企业数2004-2020年-社科数据.zip

    中国各区县工业行业企业数数据集覆盖了2004至2020年的时间跨度,提供了全国范围内区县级工业企业数量的详细统计。这些数据不仅能够反映中国工业企业的发展趋势和分布状况,而且对于研究工业行业的区域差异、发展质量和效益具有重要意义。数据集中包含了省份、地区、时间以及工业行业企业数目等关键指标,总计超过33000条数据记录。这些数据来源于各地方统计局,并经过整理,为研究者提供了一个宝贵的资源,以支持对中国经济特别是工业行业的深入分析和研究。

  • BGM坏了吗111111

    BGM坏了吗111111

Global site tag (gtag.js) - Google Analytics