`

Javascript 装载和执行

阅读更多

一两个月前在淘宝内网里看到一个优化Javascript代码的竞赛,发现有不少的人对Javascript的执行和装载的基础并不懂,所以,从那天起我就想写一篇文章,但一直耽搁了。自上篇《浏览器渲染原理简介》,正好也可以承前启后。
首先,我想说一下Javascript的装载和执行。通常来说,浏览器对于Javascript的运行有两大特性:1)载入后马上执行,2)执行时会阻塞 页面后续的内容(包括页面的渲染、其它资源的下载)。于是,如果有多个js文件被引入,那么对于浏览器来说,这些js文件被被串行地载入,并依次执行。
因为javascript可能会来操作HTML文档的DOM树,所以,浏览器一般都不会像并行下载css文件并行下载js文件,因为这是js文件的特殊性 造成的。所以,如果你的javascript想操作后面的DOM元素,基本上来说,浏览器都会报错说对象找不到。因为Javascript执行时,后面的 HTML被阻塞住了,DOM树时还没有后面的DOM结点。所以程序也就报错了。
传统的方式
所以,当你写在代码中写下如下的代码:

  1. <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. <script type="text/javascript" language="javascript">     
  2. function loadjs(script_filename) {         
  3. document.write('<' + 'script language="javascript" type="text/javascript"');         
  4. document.write(' src="' + script_filename + '">');         
  5. document.write('<'+'/script'+'>');         
  6. alert("loadjs() exit...");     
  7. }       
  8. var script = 'http://coolshell.cn/asyncjs/alert.js';      
  9. loadjs(script);     
  10. alert("loadjs() finished!"); 
  11. </script>   
  12. <script type="text/javascript" language="javascript">    
  13. alert("another block"); 
  14. </script> 
复制代码

你觉得alert的顺序是什么?你可以在不同的浏览器里试一试。这里的想关的测试页面:示例二
script的defer和async属性
IE自从IE6就支持defer标签,如:

  1. <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. function loadjs(script_filename) {     
  2. var script = document.createElement('script');    
  3.  script.setAttribute('type', 'text/javascript');     
  4. script.setAttribute('src', script_filename);     
  5. script.setAttribute('id', 'coolshell_script_id');       
  6. script_id = document.getElementById('coolshell_script_id');     
  7. if(script_id){         
  8. document.getElementsByTagName('head')[0].removeChild(script_id);     
  9. }     
  10. document.getElementsByTagName('head')[0].appendChild(script);
  11.  }   
  12. var script = 'http://coolshell.cn/asyncjs/alert.js'; 
  13. 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. var script = document.createElement("script"); 
  2. script.noexecute = true; 
  3. script.src = "alert.js"; 
  4. 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. function cachejs(script_filename){     
  2. var cache = document.createElement('object');     
  3. cache.data = script_filename;    
  4. cache.id = "coolshell_script_cache_id";     
  5. cache.width = 0;     
  6. cache.height = 0;    
  7. document.body.appendChild(cache);
  8. }
复制代码

然后,我们在的最后调用一下这个函数。请参看一下相关的示例:示例六
在Chrome下按 Ctrl+Shit+I,切换到network页,你就可以看到下载了alert.js但是没有执行,然后我们再用示例五的方式,因为浏览器端有缓存了,不会再从服务器上下载alert.js了。所以,就能保证执行速度了。
关于这种preload这种东西你应该不会陌生了。你还可以使用Ajax的方式,如:

  1. var xhr = new XMLHttpRequest(); xhr.open('GET', 'new.js'); xhr.send('');
复制代码

到这里我就不再多说了,也不给示例了,大家可以自己试试去。
最后再提两个js,一个是ControlJS,一个叫HeadJS,专门用来做异步load javascript文件的。
好了,这是所有的内容了,希望大家看过后能对Javascript的载入和执行,以及相关的技术有个了解。同时,也希望各前端高手不吝赐教!

本文转载自:酷壳网 作者:陈皓

分享到:
评论

相关推荐

    详解Javascript 装载和执行

    本文主要详细介绍了Javascript 装载和执行,并附上了详细示例,给有需要的小伙伴们参考下吧

    javascript 使用手册

    JavaScript是一种解释性编程语言,其源代码在发往客户端执行之前不需经过编译,而是将文本格式的字符代码发送给客户,由浏览器解释执行。  第四,两种语言所采取的变量是不一样的。Java采用强类型变量检查,即所有...

    javascript 装载iframe子页面,自适应高度

    假设主页面有一个div,里面放置一个iframe 代码如下:”frameBox”&gt; &lt;... height:100% ” frameborder=”0″ scrolling... 3个子页面分别在自己页面加载完[removed]执行 代码如下:function aa(){ var newHeight = docume

    javascript学习笔记.docx

    共70页,复制两页供参考,如下: 1 JavaScript基本语法 1) 读未声明的变量会产生错误。写未声明的变量会是JavaScript环境自动产生一个全局变量。...16) onload()和onunload()事件分别在网页装载完成后和卸载前执行。

    浅谈JavaScript 的执行顺序

    虽然现代浏览器可以并行的下载JavaScript(部分浏览器),但考虑到JavaScript的依赖关系,他们的执行依然是按照引入顺序进行的。 本文章记录本人在学习 JavaScript 中看书理解到的一些东西,加深记忆和并且整理记录...

    stream.js Javascript

    stream.js 是一个很小、完全独立的Javascript类库,它为你提供了一个新的Javascript数据结构:streams.Streams 是一个操作简单的数据结构,很像数组或链接表,但附加了一些非凡的能力。跟数组不一样,streams是一个...

    JavaScript_DOM编程

    ·defer 属性:该属性无值,设置该属性使得本标签在装置完后再执行,否则会在浏览器装载时局执行。 aaa &lt;script language="javascript" defer&gt; document.write("bbb"); ccc 其结果为bbb,因为在加载完后...

    stan-loader:一个非常简单的非渲染阻塞 javascript 加载器,它将按顺序加载一组库,然后在加载或错误时执行回调函数

    一个非常简单的非渲染阻塞 javascript 加载器,它将按顺序加载一组库,然后在加载或错误时执行回调函数。 将允许在 、 、 和上获得更高的分数。 它是什么/它是如何工作的 STAN Loader 是一个接受四个参数的函数; ...

    H2003032068-胡州明-SMART系统-系统框架设计与开发

    用户的浏览器在执行任务时即装载了AJAX引擎。AJAX引擎用JavaScript语言编写,通常藏在一个隐藏的框架中。它负责编译用户界面及与服务器之间的交互。AJAX引擎允许用与应用软件之间的交互过程异步进行,独立于用户与...

    jQuery中的read和JavaScript中的onload函数的区别

    这个函数的作用就是等待网页完全装载完了以后再去执行代码块内的语句,因为按照文档流的执行顺序,通常用于头部加载JavaScript的时候需要用到。 代码如下: [removed] = function(){  // 当网页加载完成后执行这里...

    JavaScript教程及实例讲解

    document.layers.position.document.close() } 如果浏览器是Netscape,就输出myclock,同时用于IE的代码就停止执行。 else if (document.all) position.innerHTML=myclock 否则,浏览器是IE,就输出myclock。 ...

    javascript常用对象梳理

    功能:打开一个新的窗口,并在窗口中装载指定URL地址的网页。 说明: open方法用于打开一个新的浏览器窗口,并在新窗口中装入一个指定的URL地址 ; open方法在打开一个新的浏览器窗口时,还可以指定窗口的名称...

    JavaScript中伪协议 [removed]使用探讨

    将javascript代码添加到客户端的方法是把它放置在伪协议说明符[removed]后的URL中。...当浏览器装载了这样的URL时,它将执行这个URL中包含的javascript代码,并把最后一条javascript语句的字符串值作

    JavaScript Event事件学习第一章 Event介绍

    这还需要知道那个函数会被执行,函数会做一些你认为的给你的网页增色的动作。这些文字描述了如何去写这样的脚本。虽然不容易,但是这是一个很让人满足的工作。 当用户做了什么事情event就发生了,当然还有一些event...

    lockandload:极简的AMD兼容Javascript和CSS加载器

    为什么查看javascript-loader情况后,寻找满足以下条件的加载器: 足够小以进行内联(避免支付额外的请求税以使装载机上装)。 内联配置文件(摆脱请求)。 纯javascript中的配置文件(无解析开销)。 让浏览器执行...

    基于javascript原生判断DOM是否加载完毕

    readyState document.readyState 返回当前文档的状态,属性如下: uninitialized 还未开始加载 loading 加载中 ...根据执行时DOM是否已经装载完毕来决定是对回调函数进行同步调用还是异步调用。具体代码如下

    JQuery中DOM加载与事件执行实例分析

    JavaScript和HTML之间的交互是通过用户和浏览器操作页面时引发的事件来处理的。当文档或者它的某些元素发生某些变化或操作时,浏览器会自动生成一个事件。例如当浏览器装载完一个文档后,会生成事件:当用户单击某个...

    如何使用headjs来管理和异步加载js

    现在有许多成熟的js模块加载器,比如requirejs和seajs等,但是对一些小的项目来说,它们...首先,我想说一下Javascript的装载和执行。通常来说,浏览器对于Javascript的运行有两大特性:1)载入后马上执行,2)执行时会

    simple-pug-loader:比帕格装载机简单

    simple-pug-loader执行相同的操作,仅在许多用例中更好。 帕格装载机的问题 帕格装载机虽然可以正常工作,但维护得不好。 它遭受许多问题的困扰,导致它不遵守正常的哈巴狗作用域规则,并且还笨拙地处理了include...

Global site tag (gtag.js) - Google Analytics