HTML中的script标签研讨

Script 的梗塞(block)特征

Scripts without async or defer attributes, as well as inline scripts, are fetched and executed immediately, before the browser continues to parse the page. – MDN

the blocking nature of JavaScript, which is to say that nothing else can happen while JavaScript code is being executed. In fact, most browsers use a single process for both user interface (UI) updates and JavaScript execution, so only one can happen at any given moment in time. The longer JavaScript takes to execute, the longer it takes before the browser is free to respond to user input. – Nicholas C. Zakas「High Performance JavaScript 」

上面援用两段话的意义大抵是,当浏览器剖析DOM文档时,一旦碰到 script 标签(没有defer 和 async 属性)就会马上下载并实行,与此同时浏览器对文档的剖析将会住手,直到 script 代码实行完成。涌现这类梗塞行动一方面是因为浏览器的UI衬着,交互行动等都是单线程操纵,另一方是因为 script 内里的代码可能会影响到背面文档的剖析,比方下面的代码:

html<script type="text/javascript">
  document.write("The date is " + (new Date()).toDateString());
</script>

这个梗塞特征会严峻的影响用户体验,下面是几种优化计划:

  • 只管把剧本往文档的背面放,以削减对文档的梗塞,最好放在 </body> 前面。
  • 只管把剧本根据它们的依靠关联放在一个文件中

不过更好的要领是下面的非梗塞加载剧本(Nonblocking Scripts)的要领:

1. Deferred Script (耽误剧本)

Script 有一个 defer 属性,具有这个属性的script表明这个script不会修正DOM,因而这段剧本会在文档树悉数剖析完成后触发( to be executed after the document has been parsed). 但这个属性并不被一切的浏览器支撑。

2. Dynamic Script Elements (动态剧本)

道理就是运用剧本建立 script 元素,设置 src 需为要动态增加剧本的 URL,再把这个 script 增加到DOM中。偶然我们须要动态剧本加载完成后再实行某些操纵,这就须要我们在剧本加载完成后增加一个回调函数,这个能够经由过程 script 的 onload 事宜完成。下面的完成代码:

jsfunction loadJS(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);
}

偶然我们须要我们动态加载的剧本根据我们加载的递次实行,但上面的完成并不能保证这一点,加载的剧本在下载完成后就会马上实行,而不会根据我们定义的递次。要处理这个题目也不难,能够参照下面的代码:

jsloadJS('a.js', function(){
  loadJS('b.js', function(){
    loadJS('c.js', function(){
      app.init();
    })
  })
})

当有大批的剧本须要动态增加时,如许写也会碰到题目;别的的处理计划是应用一些现成的库,比方 LABjs

3. XMLHttpRequest Script Injection (XHR动态插进去)

道理是应用XMLHttpReques(XHR)对象,动态猎取一段JS代码,然后插进去文档。
相对其他要领来说的一个长处是能够“懒实行”,也就是JS代码已先下载好了并没有实行,能够在须要的来实行(?)(之前的动态剧本在下载后会马上实行)。完成代码:

jsfunction xhrLoadJS (url, callback){
  var xhr = new XMLHttpRequest();
  xhr.open('get', url, true);
  xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
      if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
        var script = document.createElement('script');
        script.type = 'text/script';
        script.text = xhr.responseText;
        eval(xhr.responseText);  // 实行代码
        document.body.appendChild(script);
        callback();
      }
    }
  }
  xhr.send(null);
}

瑕玷是不能跨域要求

参考

  1. Javascript 装载和实行
  2. MDN Script元素
  3. Nicholas C. Zakas 所著的「High Performance JavaScript 」的第一章 “Loading and Execution”
    原文作者:杨军军
    原文地址: https://segmentfault.com/a/1190000002810487
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞