承接前面一篇文章《浏览器的渲染原理简介》 ,本文来说下JavaScript的装载和执行。

通常来说,浏览器对于 JavaScript 的运行有两大特性:

1) 载入后马上执行

2) 执行时会阻塞页面后续的内容(包括页面的渲染、其他资源的下载)

所以,如果有多个JS文件被引入,那么对于浏览器来说,这些JS文件将被串行地载入并依次执行。

由于JavaScript 可能会操作 HTML文档的DOM 树,所以浏览器一般都不会像并行下载CSS文件一样并行下载JS文件,这是JS文件的特殊性造成的。因此,如果你的JavaScript想操作后面的DOM 元素,浏览器会报错说找不到对象,这是因为JavaScript执行时后面的HTML被阻塞住了,操作DOM 树时还没有后面的节点。

传统方式

当你写下如下代码时:

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

基本上来说,head里的<script>标签会阻塞后续资源的载入以及整个页面的生成。比如上面这个示例,其中只有一句JS代码(示例):

alert(“hello world”) ;

效果是在加载此JS文件时会弹出一个对话框,因此点击这个对话框后才会对后续资源进行载入以及对整个页面的进行生成。

所以,有很多网站会把 js 放在网页的最后面,或者使用 window.load、$(document).ready(function(){}) 之类的事件。

另外,由于绝大多数的JavaScript代码并不需要等待页面,我们需要异步载入功能。那我们怎么异步载入呢?

document.write 方式

你可能以为 document.write() 方式能够解决不阻塞的方式。通过 document.write 方法写入<script>标签的方式就可以执行后面的东西,对于在同一个 script 标签内的 JS代码来说是这样的。但是,对于整个页面来说,还是会阻塞的。下面是一段测试代码(示例):

<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>

依此弹出的对话框为:

loadjs() exit...
loadjs() finished!
hello world
another block

然后才会显示页面。

script 的defer和async属性

IE自从IE6就之处defer 标签,如:

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

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

我们的HMTL 5也加入了一个异步载入 JavaScript的属性:async 。无论你对它赋什么样的值,只要它出现,它就开始异步加载 JS文件。但是,async的异步加载会有一个比较严重的问题,那就是它忠实的执行“载入后马上执行”这条规则。所以,虽然它并不阻塞页面的渲染,但是你也无法控制他执行的次序和时机(示例)。

支持 async 标签的浏览器如下,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方式绑定到某个事件上就可以了。

比如:

1) 绑在window.load 事件上(示例

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

2) 绑在特定的事件上(示例

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

比如当我们在点击某个DOM元素时,才载入我们的JS文件。

更多

有的人可能会觉得绑定在某个特定事件上似乎过了一点,而在点击时才载入JS又太慢了。这里抛出一个终极问题:我们想要异步地把JS文件下载到用户本地,但是又不执行,仅当我们想要执行的时候才去执行。

作者提出了一种方式,就像多年之前玩preload图片那样,我们可以动用 object 标签(也可以使用 iframe 标签),于是有了下面的代码(示例):

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 下按F12(或者Ctrl+Shit+I),切换到 network页,可以看到 alert.js 文件已经下载了但是却没有执行弹出 "hello,world"对话框的操作。然后我们再用之前“绑在特定的事件上”的方式,因为浏览器端有缓存了,不会在从服务器上下载 alert.js 文件了,这样就能保证执行速度了。

我们还可以用Ajax的方式,比如:

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

最后再提两个JS库,一个是ControlJS,一个叫HeadJS,专门用来做异步load javascript文件的。

来源:JavaScript 的装载和执行

【转】JavaScript 的装载和执行的更多相关文章

  1. javascript的装载和执行

    前言 为什么要采用js来create一个script标签,设置src然后append到head中,而不是直接使用script标签,这样不是更简单点吗? javascript的装载和执行 首先,我想说一 ...

  2. Javascript 装载和执行(copy的感觉有很多错误。。)

    copy from:http://coolshell.cn/articles/9749.html 首先,我想说一下Javascript的装载和执行.通常来说,浏览器对于Javascript的运行有两大 ...

  3. 关于JavaScript预编译和执行顺序以及函数引用类型的思考

    昨晚在对项目中的一部分做模块化处理的时候,遇到了一个问题,一个重新定义的function对一个通用类中的function进行赋值覆盖的时候,失败了.问题抽象出来是这样的: <script > ...

  4. [转]Javascript中的自执行函数表达式

    [转]Javascript中的自执行函数表达式 本文转载自:http://www.ghugo.com/javascript-auto-run-function/ 以下是正文: Posted on 20 ...

  5. 深入理解javascript中的立即执行函数(function(){…})()

    投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-06-12 我要评论 这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是 ...

  6. javascript从定义到执行 js引擎 闭包

    javascript从定义到执行,JS引擎在实现层做了很多初始化工作,因此在学习JS引擎工作机制之前,我们需要引入几个相关的概念:执行环境 栈.全局对象.执行环境.变量对象.活动对象.作用域和作用域链 ...

  7. javascript 作用域链与执行环境

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! 作用域.作用域链.执行环境.执行环境栈以及this的概念在javascript中非常重要,本人经常弄混淆, ...

  8. 怎么样加快JavaScript加载和执行效率

    概览 无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成.JavaScript 执行过程耗时越久,浏览器等待响应用户输入的时间就越长.浏览器在下载 ...

  9. javascript中的立即执行函数(function(){…})()

    javascript中的立即执行函数(function(){…})() 深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是用(function(){…})()包 ...

随机推荐

  1. Neural style transfer

    网络风格迁移 作者:无用 本文通过学习吴恩达视频所做笔记 目录 简介 可视化卷积层 构建风格迁移网络 一.网络风格迁移简介 二.可视化卷积层 可视化深层卷积网络???这个问题我看过一篇文章,我会在后补 ...

  2. Python的字符串内建函数(字符串处理)

    Python的字符串内建函数这些方法实现了string模块的大部分方法 , 如下表硕士列出了目前字符串内建支持的方法 string = 'XXX' string.capitalize() # 把字符串 ...

  3. Ext.js入门:常用组件与综合案例(七)

    一:datefield简单示例 二:timefield简单示例 三:numberfield简单示例 四:FormPanel提交   datefield简单示例: <html xmlns=&quo ...

  4. Redis的优势和特点

    Redis的特点: 内存数据库,速度快,也支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用. Redis不仅仅支持简单的key-value类型的数据,同时还提供list ...

  5. Hibernate的主配置文件hibernate.cfg.xml

    1:Hibernate的主配置文件的名字必须是hibernate.cfg.xml(主要配置文件中主要配置:数据库连接信息,其他参数,映射信息):常用配置查看源码:Hibernate\hibernate ...

  6. SQL中IN和EXISTS用法的区别

    结论 1. in()适合B表比A表数据小的情况 2. exists()适合B表比A表数据大的情况 当A表数据与B表数据一样大时,in与exists效率差不多,可任选一个使用. select * fro ...

  7. #7 //[CQOI2014]和谐矩阵

    题解: bitset优化高斯消元 无关变量为1 #include <bits/stdc++.h> using namespace std; #define eps 1e-9 #define ...

  8. 【spring基础】AOP概念与动态代理详解

    一.代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一 ...

  9. 每天减一半。问多少天这个绳子会小于5米?进而得while和for的关系

    一:前提 1.程序 2.结果 3.使用 for的条件只要>5 变化的条件是x/=2 4.进而使用while,得第二种方法 5.结果相同 二:结论 程序可以使用for的必将可以使用while. 其 ...

  10. Cpu 主频与睿频

    主频就是一颗CPU的运行频率.比如一颗CPU是2.3G,无论是单核还是多核,所有的核心都是工作在2.3G. 睿频是Intel的一项加速技术,指当启动一个运行程序后,处理器会自动加速到合适的频率,而原来 ...