zoukankan      html  css  js  c++  java
  • 浏览器中Javascript的加载和执行

    在刚学习Javascript时曾对该问题在小组内做个一次StudyReport,发现其中的基础还是值得分析的。 

    从标题分析,可以加个Javascript的加载和执行分为两个阶段:加载、执行。而加载即浏览器下载JS脚本的过程,执行时浏览器JS引擎解释执行的过程。

    接下来先分析JS脚本加载的过程,加载方式可分为同步加载和异步加载。

    同步加载即浏览器加载JS过程中停止对HTML元素的解析,保证JS执行的安全一致性,但如果JS中包含大量计算时,会导致阻塞页面的渲染。常见的JS加载是通过<script>标签置于<head>内加载,这种方式会导致加载时阻塞对HTML元素的渲染,导致页面短暂空白。因此,建议将<script>便签置于</body>前,可以在HTML渲染完成后加载JS文件。即,

    传统加载方式:

    <head>
    <script src='yourscript.js'></script>
    </head>
    <body></body>

    推荐加载方式:

    <head></head>
    <body>
    ...
    <script src='yourscript.js'>
    </script>
    </body>

    使用一个例子加上一张序列图来描述HTML加载JS/CSS的流程,其中各个步骤均是同步的,会阻塞下一步解析。

    <html>
    <head>
    <link></link>
    <script><script>
    </head>
    <body>
    <div></div>
    <script></script>
    </body>
    </html>
    

      

    异步加载也称动态加载,即在后期动态加载JS。常见的动态JS加载有以下几种方式。

    1.document.write('yourscript.js');//这种方式在各浏览器行为不一致

    2.动态修改<script></script>的src

    3.动态插入<script>标签,可在<script>脚本中,也可在onload中

    <script> 
        var s = document.createElement('script'); 
        s.type = 'text/javascript'; 
        s.src = 'yourscript.js'; 
        var x = document.getElementsByTagName('script')[0]; 
        x.parentNode.insertBefore(s, x); 
    </script> 

    4.XHR结合eval

    var xhr = new XmlHttpRequest();
    xhr.onreadstatechange = function(){
        if(xhr.readyState==4)
        {
            if(xhr.status==200)
            {
                 eval(xhr.responseText);
             }
        }
    }
    xhr.open("GET",yourscript.js',true);
    xhr.send(null);
    

    5.defer和async属性。

    <script src='yourscript.js' async/defer ></script>

    二者都在onload之前执行完成,可用于不修改DOM的JS脚本加载。不同之处在与,defer下载的JS按顺序执行,而async不能保证执行顺序。

    接下来分析脚本的执行流程。执行可分为解释与执行两个过程。

    在脚本解释的过程中,会对var和function做不同的处理,var定义的对象赋值undefined,而function定义的对象赋值为函数体。

    我们用示例来解释上面的意思。首先看解释器对var的处理。

    <script>
        alert(i); // undefined
        var i = 1;
        alert(i); 
    </script>

    上述代码在解释器中进行转换为:

    <script>
        var i;
        alert(i); // undefined
        i = 1;
        alert(i); 
    </script>
    

    这样就能理解为什么i值为undefinded。接下来我们看看对function的处理。

    <script>
        alert(func); // function(){alert('out')}
        var func = function(){
            alert('out');
        };
        alert(func); 
    </script>
    

    上述代码在解释器中进行转换为:  

    <script>
        var func = function(){
            alert('out');
        };
        alert(func); // function(){alert('out')}
        alert(func); 
    </script>
    

    这就是解释器对var和function的不同处理,function的声明和函数体定义都会被提前。

    另外,脚本解释过程中,以<script>以块为单位执行,块间可共享变量。对外部脚本会将JS加载完成并执行,而且JS脚本在执行的过程中会阻塞后续HTML页面的渲染。

    <script>
        alert(i); // error 该块内后续代码不执行
        i = 1;
        alert(i); 
    </script>
    <script>
        var j=0;    
        alert(j); //
    </script>
    

    上面这个例子解释了脚本以块为单位执行的原理,虽然第一个<script>会报异常,但并不影响第二个<script>的执行。

    <script>
        var i = 1;
        alert(i); //1
    </script>
    <script>
        alert(i); //1
    </script>
    

    通过上例结果,可解释两个<script>之间是可以共享变量的。这也就是为什么加载jquery.min.js后,在任何<script>中都可以使用$来引用jQuery。 

    关于浏览器加载JS并执行的过程暂时描述到此,后期继续补充。

  • 相关阅读:
    十个能让你成为牛逼前端程序猿的特征
    一道Javascript面试题引发的血案
    程序员实现财务自由的9个阶段,你达到了哪一段?
    程序员进阶路上不能错过的史上最全技术知识图谱秘籍
    清华大学研发神技能:用意念回复微信
    机器学习原来如此有趣:用深度学习识别人脸
    【代码片段】如何使用CSS来快速定义多彩光标
    Android自定义一款带进度条的精美按键
    现在的人工智能逆天到什么地步了?
    分享几套生成iMac相关高逼格免费mockup的素材和在线工具
  • 原文地址:https://www.cnblogs.com/tesky0125/p/4619554.html
Copyright © 2011-2022 走看看