# 1. 加载和执行

  1. 多数浏览器使用单一进程来处理用户界面(UI)刷新和javascript脚本执行,所以同一时刻只能做一件事。这是页面生存周期中的必要环节,因为脚本执行中可能会修改页面内容。
  2. 以下代码中file1.js会先下载再执行。然后file2.js下载再执行。最后file3.js下载再执行。
<head>
  <script src='file1.js'></script>
  <script src='file2.js'></script>
  <script src='file3.js'></script>
</head>
1
2
3
4
5
  1. script标签中async与defer相同点是采用并行下载,在下载过程中不会产生阻塞。区别在于执行时机,async是加载完成后自动执行,而defer需要等待页面完成后执行(onload事件被触发前执行),defer属性尽当src属性声明时才生效。
<head>
  <script src='file1.js' defer></script>
</head>
1
2
3
  1. 动态脚本元素
function loadscript(url,callback){
  var script=document.createElement('script');
  script.type='text/javascript';

  if(script.readyState){
    //IE
    script.onreadystatechange=function(){
      if(script.readyState=='loaded'||script.readyState=='complete'){
        script.onreadystatechange=null;
        callback();
      }else{
        //其他浏览器
        script.onload=function(){
          callback();
        }
      }
      script.src=url;
      document.getElementsByTagName('head')[0].appendChild(script);
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

文件在该元素被添加到页面时开始下载。这种技术重点在于:无论在何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。动态脚本加载凭借着它在跨浏览器兼容性和易用的优势,成为最通用的无阻塞加载的解决方案。

  1. XMLHttpRequest脚本注入
var xhr=new XMLHttpRequest();
xhr.open=('get','file.js',true);
xhr.onreadystatechange=function(){
  if(xhr.readyState==4){
    if(xhr.status>=200&&xhr.status<300||xhr.status==304){
      //304意味着是从缓存读取
      var script=document.createElement('script');
      script.type='text/javascript';
      script.text=xhr.responseText;
      document.body.appendChild(script);
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

一旦新创建<script>元素被添加到页面,代码就会立刻执行然后准备就绪。 这种方法的有点是你可以js但是不立即执行。可以推迟到你准备好的时候。

  1. LazyLoad类库 LazyLoad是loadscript()函数的增强版。
LazyLoad.js(['first.js','second.js'],function(){
  //...
})
1
2
3

每次下载仍然是一个独立的http请求,而且回调函数会等待所有文件都下载完成后才会执行。

# 总结

  1. 将所有<script>标签放到body闭合标签前,确保脚本执行前已经完成了渲染。
  2. 合并脚本。页面中的script标签越少,加载就越快,响应也更迅速。
  3. 有多种无阻塞下载js的方法:
  • 使用<script>标签的defer属性。
  • 使用动态创建的<script>标签下载并执行代码。
  • 使用XHR对象下载js代码并注入页面中。