Javascript 装载和执行

作者:陈皓(花名:钻风)

 

首先,我想说一下Javascript的装载和执行。通常来说,浏览器对于Javascript的运行有两大特性:1)载入后马上执行,2)执行时会阻塞页面后续的内容(包括页面的渲染、其它资源的下载)。于是,如果有多个js文件被引入,那么对于浏览器来说,这些js文件被被串行地载入,并依次执行。

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

 

传统的方式

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


1

2

<script type="text/javascript"

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

 

基本上来说,head里的 <script>标签会阻塞后续资源的载入以及整个页面的生成。我专门做了一个示例你可以看看:示例一。 注意:我的alert.js中只有一句话:alert(“hello world”) ,这更容易让你看到javascript是怎么阻塞后面的东西的。

所以,你知道为什么有很多网站把javascript放在网页的最后面了,要么就是动用了window.onload或是docmuemt ready之类的事件。

另外,因为绝大多数的Javascript代码并不需要等页面,所以,我们异步载入的功能。那么我们怎么异步载入呢?

 

document.write方式

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


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<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标签,如:


1

2

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

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


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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的执行的情况,你就知道不同了)


1

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

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


1

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

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

 

更多

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

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


1

2

3

4

5

6

7

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。如:


1

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

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

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


1

2

3

4

5

6

7

8

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+Shit+I,切换到network页,你就可以看到下载了alert.js但是没有执行,然后我们再用示例五的方式,因为浏览器端有缓存了,不会再从服务器上下载alert.js了。所以,就能保证执行速度了。

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


1

2

3

var xhr = new XMLHttpRequest();

xhr.open('GET', 'new.js');

xhr.send('');

到这里我就不再多说了,也不给示例了,大家可以自己试试去。

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

好了,这是所有的内容了,希望大家看过后能对Javascript的载入和执行,以及相关的技术有个了解。同时,也希望各前端高手不吝赐教!

(全文完)

时间: 2025-01-26 16:56:30

Javascript 装载和执行的相关文章

高性能Javascript 装载和执行实例教程

首先,我想说一下Javascript的装载和执行.通常来说,浏览器对于Javascript的运行有两大特性:1)载入后马上执行,2)执行时会阻塞页面后续的内容(包括页面的渲染.其它资源的下载).于是,如果有多个js文件被引入,那么对于浏览器来说,这些js文件被被串行地载入,并依次执行. 因为javascript可能会来操作HTML文档的DOM树,所以,浏览器一般都不会像并行下载css文件并行下载js文件,因为这是js文件的特殊性造成的.所以,如果你的javascript想操作后面的DOM元素,基

javascript 终止函数执行操作

 本篇文章主要是对javascript 终止函数执行的操作方法进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助 1.如果终止一个函数的用return即可,实例如下: function testA(){     alert('a');     alert('b');     alert('c'); } testA(); 程序执行会依次弹出'a','b','c'.   function testA(){     alert('a');     return;     alert('b');

ThinkPHP控制器里javascript代码不能执行的解决方法_php实例

本文实例讲述了ThinkPHP控制器里javascript代码不能执行的解决方法.分享给大家供大家参考.具体方法如下: 这里实例分析一下thinkphp在控制器里的网页特效代码不能执行解决方法,就拿"退出"这一项来说吧,我的"退出系统"链接是写到左边的框架里的,用js动态生成的.也就是说,没法通过链接里的target来指定. 复制代码 代码如下: $this->assign('jumpurl',__url__.'/login');<br>$this

javascript中强制执行toString()具体实现_javascript技巧

原文:Enforcing toString() 译文:javascript 中强制执行 toString() 译者:singleseeker Javascript通常会根据方法或运算符的需要而自动把值转成所需的类型,这可能导致各种错误. Brian McKenna (@puffnfresh) suggests 提供了下列测试代码: 复制代码 代码如下: Object.prototype.valueOf = function () { throw new Error('Use an explici

js函数 执行方式-javascript函数的执行方式?

问题描述 javascript函数的执行方式? javascript函数有哪些执行方式,有高手帮忙总结一下吗? 解决方案 不知道你说的方式按照什么分类,和别的编程语言类似,js的函数从调用方式上分为普通函数和回调函数,从定义方式看,分为命名函数和匿名函数,从调用者来说,分为递归函数和非递归函数. 解决方案二: 匿名(function(i){alert(i)})(11)显示申明的function func(i){alert(i)}func(1)变量式var func=function(i){ale

[WebKit] JavaScriptCore解析--基础篇(四) 页面解析与JavaScript元素的执行

很多地方都已经介绍了JavaScript在浏览器是如何被执行的,这里介绍一下WebKit是如何实现的.主要涉及JS的async,defer及普通脚本的解析与执行过程的代码实现. 1. 概要说明 先概要说明一下浏览器如何执行JavaScript的. 首先浏览器的页面解析器(Document Parser)遇到<script>就会发起下载(脚本内容在页面内的就不用下载了).然后针对不同情况执行的方式有所不同:   . async (在script标签中启用了async属性)       这是异步执

嵌套的javascript 用children[0]为什么javascript代码没有执行呢

问题描述 嵌套的javascript 用children[0]为什么javascript代码没有执行呢 <head> <title>后台左侧导航页面</title> <style type="text/css"> .dc { display: none; margin-left: 10px; } </style> <script language="javascript"> function t

探讨JavaScript语句的执行过程_javascript技巧

废话不多说,直奔主题了.javascript的运行原理总结如下: 1.按照html文档流顺序执行javascript代码 浏览器是按照文档流从上到下逐步解析页面结构和信息的,javascript代码作为嵌入的脚本作为html文档的组成部分,所以javascript代码在加载时的执行顺序也是根据脚本标签<script>的出现顺序来确定的. 如果通过脚本标签<script>的src属性来引入外部.js文件,那么它也将按照其语句出现的顺序来执行,而且执行过程是文档加载的一部分.不会因为是

javascript系列之执行上下文

原文:javascript系列之执行上下文       写在前面:一 直想系统的总结一下学过的javascript知识,喜欢这门语言也热爱这门语言.未来想从事前端方面的工作,提前把自己的知识梳理一下.前面写了些 DOM的知识,略觉水平有限.没几个月就要开赴找工作的前线,奈何自己还是个菜鸟,具体写的时候还没有一个完整的思路.多番考虑之后,决定还是翻译外国的 经典系列文章,总结提升的同时,英语水平也可以上一个台阶,双管齐下,相信对以后肯定有好处.当然这个系列的文章已经有好多人翻译过了,水平都挺高(我