【高性能JavaScript】读书笔记 - 引入脚本(二) - 02

    xiaoxiao2021-03-25  71


    【简介】通过动态脚本的方式加载js脚本文件,利用其异步的过程实现了无阻塞脚本的效果,但是对于需要同步处理的脚本,就需要再将其同步化,或者采用我们之前的直接将脚本文件放在body尾部加载的方式。

    1. 无阻塞的脚本(Noblocking Scripts)

    减少JavaScript文件数量并限制HTTP请求的数量虽然能够提高加载效率,但随着Web应用的功能的丰富,所需要的JavaScript代码就越多,单个的JS文件也会使浏览器死锁一段时间。为了避免这种情况,我们需要向页面逐步加载JS文件,减少浏览器的阻塞。 通过这样的方式加载的脚本,我们称之为无阻塞的脚本(Noblocking Scripts)。

    2. 动态脚本元素(Dynamic Script Elements)

    通过DOM操作创建一个 <script> 标签的方式称之为动态脚本元素(Dynamic Script Elements)。 这种技术的重点在于:无论在合适启动下载脚本,文件的下载和执行都不会阻塞页面其他进程。

    一般有以下三种方式实现:

    第一种:document.write写入

    document.write("<script src='package.js'><\/script>");

    这种方法中document.write会重写页面,基本上不能用。

    第二种:动态改变 <script> 的src属性

    <script type="text/javascript" id="loadScript"></script> <script type="text/javascript"> loadScript = document.getElementById("loadScript"); loadScript.src = 'package.js'; </script>

    这种方式需要些两个<script> 标签,不符合我们上一讲中尽量减少<script> 标签数量的优化目标。

    第三种:动态创建<script> 元素

    <script type="text/javascript"> var myScript = document.createElement('script'); myScript.type = "text/javascript"; myScript.src = "package.js"; document.body.appendChild(myScript); </script>

    这种方式的动态脚本较优。

    这三种方式都是异步的(脚本的加载不影响主页面程序继续往下执行),所以,如果当异步加载的脚本文件,会被主页面程序马上调用,就会无法正常执行。

    比如,我们有一个package.js的脚本文件,里边有一个function,在这个函数中有一些代码,我们以一个alert弹框作为代码。

    function packageFun(){ alert("成功加载"); }

    在另一个demo.html中,我们通过一个button来测试这个异步的过程。

    <!DOCTYPE html> <html> <head> <title>动态脚本</title> <meta charset="utf-8"> <script type="text/javascript"> function init(){ var myScript = document.createElement('script'); myScript.type = "text/javascript"; myScript.src = "package.js"; document.body.appendChild(myScript); document.write("<input type='button' value='测试运行效果' onclick='operation()'>"); packageFun(); } function operation() { packageFun(); } </script> </head> <body> <input type="button" value="初始化加载" onclick="init()"> </body> </html>

    运行的结果是第一次点击button,没有alert出弹框,第二次点击document write出来的button,出现alert弹框。 原因在于,第一次点击button的时候,调用了init()方法,这个方法加载了script,这时就会引入package.js文件,在引入js文件的过程中,程序又继续执行,运行到packageFun()方法的时候,因为此时package.js文件还未加载完全,就找不到packageFun()这个方法(大家不要忘记packageFun()在package.js文件中),这个过程就是一个异步过程。 而第二次点击button的时候,执行packageFun()方法,因为在第一次点击button的时候,已经将package.js文件引入了,所以就能找到packageFUn()这个方法,所以就能alert出弹框。

    如果遇到引入的js文件需要马上被调用,就需要将异步过程同步化,也就是让js文件完全加载后,再执行后面的代码。

    <!DOCTYPE html> <html> <head> <title>异步脚本同步化</title> <meta charset="utf-8"> <script type="text/javascript"> function loadScript(url, callback){ var script = document.createElement('script'); script.type = "text/javascript"; if (script.readyState) { // 判断是IE浏览器 alert("IE浏览器"); script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete") { script.onreadystatechange = null; callback(); } } } else { // 判断是其他浏览器 alert("其他浏览器"); script.onload = function() { callback(); } } script.src = url; document.getElementsByTagName('head')[0].appendChild(script); } loadScript("package.js", function(){ packageFun(); }); </script> </head> <body> </body> </html>

    这段代码中,关于对IE兼容性处理的部分不做过多介绍,如果对这部分不太了解的同学,可以百度一下相关的内容。

    这段代码的核心在于,封装的loadScript()方法,通过监听脚本js文件完全加载的事件后,再执行callback回调函数中的内容,而要执行package.js文件中的内容,就放在这个回调函数中,模拟实现了先加载完全脚本文件,后执行callback函数中的代码的过程。

    参考资料: [1]js动态加载脚本(http://www.cnblogs.com/zhuimengdeyuanyuan/archive/2013/03/06/2946277.html)

    附: 欢迎大家关注我的新浪微博 - 一点编程,了解最新动态 。

    转载请注明原文地址: https://ju.6miu.com/read-32768.html

    最新回复(0)