【转】JavaScript 的装载和执行

承接前面一篇文章《浏览器的渲染原理简介》 ,本文来说下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 的装载和执行

时间: 2024-10-06 06:20:02

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

Javascript 装载和执行

转自:http://coolshell.cn/articles/9749.html#more-9749 一两个月前在淘宝内网里看到一个优化Javascript代码的竞赛,发现有不少的人对Javascript的执行和装载的基础并不懂,所以,从那天起我就想写一篇文章,但一直耽搁了.自上篇<浏览器渲染原理简介>,正好也可以承前启后. 首先,我想说一下Javascript的装载和执行.通常来说,浏览器对于Javascript的运行有两大特性:1)载入后马上执行,2)执行时会阻塞页面后续的内容(包括页面

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

javascript中的立即执行函数(function(){…})() 深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是用(function(){…})()包住业务代码,使用jquery时比较常见. ( function(){…} )()和( function (){…} () )是两种javascript立即执行函数的常见写法,最初我以为是一个括号包裹匿名函数,再在后面加个括号调用函数,最后达到函数定义后立即执行的目的,后来发现加括号的原因并非如此.要

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

概览 无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成.JavaScript 执行过程耗时越久,浏览器等待响应用户输入的时间就越长.浏览器在下载和执行脚本时出现阻塞的原因在于,脚本可能会改变页面或 JavaScript 的命名空间,它们对后面页面内容造成影响.一个典型的例子就是在页面中使用document.write(). JavaScript 代码内嵌示例 <html> <head> <title>Source

【JS】JavaScript引擎的内部执行机制

 近期在复习JavaScript,看到setTimeout函数时.想起曾经刚学时,在一本书上看过setTimeout()里的回调函数执行的间隔时间有昌不是后面设置的值.曾经没想太多.网上看了JS大神的解释,整理记录下JavaScript引擎的内部执行机制. 首先看一段小程序: <script> alert('第1'); setTimeout(function(){alert('第2');}, 2000); alert('第3'); </script> 输出顺序是:第1.第3,第

javascript 从定义到执行,你应该知道的那些事

javascript从定义到执行,JS引擎在实现层做了很多初始化工作,因此在学习JS引擎工作机制之前,我们需要引入几个相关的概念:执行环境栈.全局对象.执行环境.变量对象.活动对象.作用域和作用域链等,这些概念正是JS引擎工作的核心组件.这篇文章的目的是孤立的为你讲解每一个概念,而是通过一个简单的demo来展开分析,全局讲解JS引擎从定义到执行的每一个细节,以及这些概念在其中所扮演的角色. var x = 1; //定义一个全局变量 x function A(y){ var x = 2; //定

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

javascript从定义到执行,JS引擎在实现层做了很多初始化工作,因此在学习JS引擎工作机制之前,我们需要引入几个相关的概念:执行环境 栈.全局对象.执行环境.变量对象.活动对象.作用域和作用域链等,这些概念正是JS引擎工作的核心组件.这篇文章的目的是孤立的为你讲解每一个概念,而 是通过一个简单的demo来展开分析,全局讲解JS引擎从定义到执行的每一个细节,以及这些概念在其中所扮演的角色. var x = 1;  //定义一个全局变量 x function A(y){ var x = 2; 

javascript运行机制之执行顺序

前言 JavaScript是一种描述型脚本语言,它不同于java或C#等编译性语言,它不需要进行编译成中间语言,而是由浏览器进行动态地解析与执行.如果你不能理解javaScript语言的运行机制,或者简单地说,你不能掌握javascript的执行顺序,那你就犹如伯乐驾驭不了千里马,让千里马脱缰而出,四处乱窜. 那么JavaScript是怎么来进行解析的吗?它的执行顺序又是如何的呢?在了解这些之前,我们先来认识几个重要的术语: 代码块 JavaScript中的代码块是指由<script>标签分割

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

这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是用(function(){-})()包住业务代码,使用jquery时比较常见,需要的朋友可以参考下http://www.jb51.net/article/50967.htm javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花,当然,能理解各型各色的写法也是对javascript语言特性更进一步的深入理解. ( function()

javascript中的立即执行函数

javascript中的立即执行函数$(function(){ alert();}()) Highcharts的中的 series:[{ name: '今日在线人数', color: 'pink', data: (function(){ )()) }] #执行效果一样$( document ).ready(function() { console.log( "ready!" ); }); 和 $(function() { console.log( "ready!"