Home  >  Article  >  Web Front-end  >  Several JavaScript asynchronous loading related issues

Several JavaScript asynchronous loading related issues

小云云
小云云Original
2018-02-22 09:06:541591browse

The default js is loaded synchronously. The "loading" here can be understood as parsing and execution, rather than "downloading". In the latest version of the browser, the browser uses a waterfall style for the resources requested by the code. Loading is not blocking, but the execution of js is always blocking. What problems does this cause? If my index page needs to load some js, but one of the requests does not get a response for a long time, it blocks the execution of the subsequent js code (synchronous loading), and the page rendering cannot continue (if the js introduction is in the head after the label).


<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
this is a test

For example, the above code is saved as an index.html file. The main body of the page is a simple string, but after the code is executed, the page remains blank. , why? Because the requested js cannot be loaded for a long time (possibly due to Google being blocked, etc.), the execution of the subsequent code is blocked and the page cannot be rendered. Maybe you will suggest that if you put the js code before 36cc49f0c466276486e50c850b7e4956, the page will be rendered first! Good method, we try to put js behind:


this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>

The page is rendered instantly, "this is a test" also quickly appears in the foreground, and the world seems to be calm, However:


this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>

I simply added a piece of code based on the previous code, but "hello world" cannot be output on the console. Obviously, the previous js request is blocked. When loading the code behind, we suddenly realized that changing the loading position of js can only change the rendering of the page. However, it is of no use to the loading of js, and js will still block.

Implementing js asynchronous loading

Our requirement seems to be very simple. It can output a string in the console while the page is loading. To put it more simply, it is to request the first While segmenting the js provided by Google, continue to execute the following js, which is to implement asynchronous loading of js.

The most common approach is to dynamically generate script tags:


<body>
 this is a test
 <script type="text/javascript">
  ~function() {
   var s = document.createElement(&#39;script&#39;);
   s.src = &#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39;;
   document.body.appendChild(s);
  }();
 </script>
 <script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
 <script type="text/javascript">
  console.log(&#39;hello world&#39;);
 </script>
</body>

But there is still a problem. This loading method will prevent the onload event before the loading is completed. Triggered, and now the code of many pages has to perform additional rendering work when onloading, so it will still block the initialization processing of some pages:


<body>
 this is a test
 <script type="text/javascript">
  ~function() {
   // function async_load() {
    var s = document.createElement(&#39;script&#39;);
    s.src = &#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39;;
    document.body.appendChild(s);
   // }
   // window.addEventListener(&#39;load&#39;, async_load, false);
  }();

  window.onload = function() {
   var txt = document.createTextNode(&#39; hello world&#39;);
   document.body.appendChild(txt);
  };
 </script>
 <script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
</body>

For example, the above The code cannot render "hello world" well. We only need to remove the comments and let the js provided by Google start loading asynchronously on onload. This solves the problem of blocking the onload event from being triggered.

Added DOMContentLoaded and OnLoad events DOMContentLoaded: The page (document) has been parsed and the dom elements in the page are available. However, the images and subframes referenced in the page may not have been loaded yet. OnLoad: All resources of the page are loaded (including images). The browser's loading progress stops at this point. These two time points divide the page loading timeline into three stages.

The above seems to be a better solution to this problem, but html5 provides a simpler method, the async attribute!


this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39; async=&#39;async&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
<script type="text/javascript">
 console.log(&#39;hello world&#39;);
</script>

async is a new attribute of html5. The async attribute specifies that once the script is available, it will be executed asynchronously (it will be executed immediately once downloaded).

It should be noted that the async attribute only applies to external scripts (only when using the src attribute)

The defer attribute is often mentioned together with async:


this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39; defer=&#39;defer&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
<script type="text/javascript">
 console.log(&#39;hello world&#39;);
</script>

It seems that the implementation effect is similar, but is it really the same? Let's take a look at the definition of the defer attribute.

In the past, defer only supported IE hacks, but now the emergence of HTML5 has begun to fully support defer. The defer attribute specifies that the script will not be executed until the page has finished loading. The defer attribute only applies to external scripts (only when using the src attribute). ps: The defer supported by IE does not seem to be the case, because I have no interest in IE and will not delve into it. If you are interested, you can check the relevant information.

Since async and defer often appear together, let’s analyze them!

If there are no async and defer attributes (assigned to true, the same below), the browser will immediately execute the current js script and block subsequent scripts; if there is an async attribute, the process of loading and rendering subsequent document elements It will be done in parallel with the loading and execution of the current js (asynchronously); if there is a defer attribute, then the process of loading subsequent document elements will be done in parallel with the loading of script.js (asynchronously), but the execution of script.js will be done in all elements ( DOM) parsing is completed, but before the DOMContentLoaded event is fired.

Let’s take a look at a picture stolen from the Internet:

The blue line represents network reading, and the red line represents execution time, both of which are for scripts ; the green line represents HTML parsing.

This picture tells us the following key points (excerpted from the difference between defer and async):

  1. defer and async are the same in terms of network reading (downloading) , both are asynchronous (compared to HTML parsing)

  2. The difference between them lies in when the script is executed after it is downloaded. Obviously defer is the closest to our application script loading and execution Requirements

  3. 关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用

  4. async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行

  5. 仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,最典型的例子:Google Analytics

但是在我看来(以下个人理解,如有出入还望指出),defer在异步加载上的应用并不会比async广。async的英文解释是异步,该属性作用在脚本上,使得脚本加载(下载)完后随即开始执行,和动态插入script标签作用类似(async只支持h5,后者能兼容浏览器);而defer的英文解释是延迟,作用也和字面解释类似,延迟脚本的执行,使得dom元素加载完后才开始有序执行脚本,因为有序,所以会带来另一个问题:


this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39; defer=&#39;defer&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39; defer=&#39;defer&#39;></script>
<script type="text/javascript" src=&#39;index.js&#39; defer=&#39;defer&#39;></script>
console.log(&#39;hello world&#39;);

如果执行这段代码,控制台的“hello world”也会迟迟得不到结果。所以我觉得还是async好用,如果要考虑依赖的话,可以选择requirejs、seajs等模块加载器。

总结

JavaScript的异步加载还有一些方式,比如:AJAX eval(使用AJAX得到脚本内容,然后通过eval(xmlhttp.responseText)来运行脚本)、iframe方式等。

相关推荐:

Angular结合zTree异步加载节点数据实例分享

JavaScript文件的同步和异步加载的实现代码

使用DataTable插件实现异步加载数据详解


The above is the detailed content of Several JavaScript asynchronous loading related issues. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn