This time I will bring you a detailed explanation of asynchronous loading of JavaScript, and what are the precautions for handling asynchronous loading of JavaScript. The following is a practical case, let's take a look.
The problem of synchronous loading
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 loads the resources requested by the code in a waterfall style instead of blocking, but the execution of js is always blocked. 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='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></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 , the page will be rendered first! Good method, we try to put js behind:
this is a test <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
The page is rendered instantly, "this is a test" also quickly appears in the foreground, the world seems to be calm, but:
this is a test <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
We simply added a piece of code based on the previous code, but "hello world" could not be output on the console for a long time. Obviously, the previous js request blocked the loading of the following code. We suddenly realized that changing the loading position of js can only change the page. Rendering, however, is of no use to loading js, js will still block.
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 achieve asynchronous loading of js.
The most common way is to dynamically generate script tags:
<body> this is a test <script type="text/javascript"> ~function() { var s = document.createElement('script'); s.src = 'http://china-addthis.googlecode.com/svn/trunk/addthis.js'; document.body.appendChild(s); }(); </script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> console.log('hello world'); </script> </body>
But there is still a problem. This loading method will prevent the onload event from being triggered before the loading is completed. Now many page codes Additional rendering work is performed during onload, 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('script'); s.src = 'http://china-addthis.googlecode.com/svn/trunk/addthis.js'; document.body.appendChild(s); // } // window.addEventListener('load', async_load, false); }(); window.onload = function() { var txt = document.createTextNode(' hello world'); document.body.appendChild(txt); }; </script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> </body>
For example, the above code cannot render "hello world" well, we only need to remove the comments That's it, 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='http://china-addthis.googlecode.com/svn/trunk/addthis.js' async='async'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> console.log('hello world'); </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 as soon as it is 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='http://china-addthis.googlecode.com/svn/trunk/addthis.js' defer='defer'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> console.log('hello world'); </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: 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.
来看一张网上盗的图:
蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。
此图告诉我们以下几个要点(摘自defer和async的区别):
defer 和 async 在网络读取(下载)这块儿是一样的,都是异步的(相较于 HTML 解析)
它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的
关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用
async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行
仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,最典型的例子:Google Analytics
但是在我看来(以下个人理解,如有出入还望指出),defer在异步加载上的应用并不会比async广。async的英文解释是异步,该属性作用在脚本上,使得脚本加载(下载)完后随即开始执行,和动态插入script标签作用类似(async只支持h5,后者能兼容浏览器);而defer的英文解释是延迟,作用也和字面解释类似,延迟脚本的执行,使得dom元素加载完后才开始有序执行脚本,因为有序,所以会带来另一个问题:
this is a test <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js' defer='defer'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js' defer='defer'></script> <script type="text/javascript" src='index.js' defer='defer'></script> console.log('hello world');
如果执行这段代码,控制台的“hello world”也会迟迟得不到结果。所以我觉得还是async好用,如果要考虑依赖的话,可以选择requirejs、seajs等模块加载器。
JavaScript的异步加载还有一些方式,比如:AJAX eval(使用AJAX得到脚本内容,然后通过eval(xmlhttp.responseText)来运行脚本)、iframe方式等。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
The above is the detailed content of Detailed explanation of asynchronous loading of JavaScript. For more information, please follow other related articles on the PHP Chinese website!