美文网首页
客户端的JavaScript(一)

客户端的JavaScript(一)

作者: 感觉不错哦 | 来源:发表于2018-12-03 14:12 被阅读47次

    说到客户端的JavaScript,很容易联想到服务器端的JavaScript,服务器的JavaScript最常见最火的也就是node了,还有一个Rhino也是服务器端的JavaScript

    今天主要聊聊客户端的JavaScript,也叫做web浏览器中的JavaScript,Window对象是所有客户端JavaScript特性和API的主要接入点

    客户端的this与node的this

    Window是客户端JavaScript下特有的对象,简单举几个例子聊聊this

    然而这时浏览器端的JavaScript,node中不存在window,之前我在对象详解中聊过,JavaScript在浏览器中运行时会生成一系列的全局对象、属性、函数,node不存在window如果运行打印window是会报错的

    node中的this

    https://www.cnblogs.com/pssp/p/5321506.html
    这篇文章可以参考,针对node基础的小伙伴,无基础可以跳过

    Web浏览器中的Web页面

    一些静态信息的页面,我们称之为文档(document)(由于加入了JavaScript,静态信息看上去会动来动去,但信息本身是静态的),相对于文档来说,其他的Web页面则感觉看上去更像是应用,类似数据交互,数据存储,看起来更像是图形化,而非文本化

    Window对象是所有客户端JavaScript特性和API的主要接入点,它表示Web浏览器的一个窗口或窗体,使用window标识符来引用它,Window下所有的属性方法都可以打印window查看,比如常见的location属性,定时器方法,主要提点比较常用原生操作的到的属性

    事件处理程序

    事件处理程序可以让JavaScript代码修改窗口、文档、和组成文档的元素的行为。事件处理程序的属性名是以单词‘on’开始的,比如说:

    elemnet.onclick=function(){this.innerHTML = new Date().toString()}
    

    Window对象中onload处理程序是最重要的事件处理程序之一。当显示窗口中的文档内容稳定并可以操作时会触发它, 更多事件后续简单提点(内容太多,也不知道自己可以写多少)

    Web应用里的JavaScript

    JavaScript程序可以Document对象和它包含的Element对象遍历管理文档内容,比如说它可以通过操作css样式和类,修改文档内容的呈现,并且可以通过注册适当的事件处理程序来定义文档元素的行为。内容、呈现和行为的组合,叫做动态HTML或DHTML

    JavaScript在web文档中的作用更多的是增强用户体验,使信息获取和传递更加容易,用户的体验不应依赖于JavaScript,不要因为你的‘秀’而成为了一个bug web程序员

    在HTML中的JavaScript

    最常见的就是内联,我们把JavaScript代码放置在<srcipt></script>标签中
    其次放置在由<script>标签的src属性指定的外部文件中(使用src的优点可以百度一下,一些面试会提及)
    放置在HTML事件处理程序中
    放在一个URL里,这个URL使用特殊的“JavaScript:”协议

    如果是XHTML(了解一下)

        <script <![CDATA[
    
        //JavaScript代码
    
        ]]></script>
    

    HTML中的事件处理,我们有时候偷懒的效果就可以使用下方的操作

    <button onclick="alert(1)">GET</button>
    

    URL中的JavaScript了解一下(英语应该是有毛病的,请不要学)

    <a href="javascript:new Date().toLocaleTimeString()">What is a time</a>
    

    defer async

    当JavaScript第一次添加到Web浏览器时,还没有API可以用来遍历文档的结构和内容,JavaScript唯一可以影响文档内容的方法就是快速生成内容,使用docum.write()方法,大家初学js的时候有没有写过这样的代码,我是敲了好几遍,我再来敲一下

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
        </head>
        <body>
    
        <h1>Table of Function</h1>
    
        </body>
            <script>
                function  factorial(n){
                    if(n<=1){
                        return n
                    }else{
                        return n*factorial(n-1) //n的阶乘
                    }
                }
                document.write('<table>')
                document.write("<tr><th>n</th><th>n!</th></tr>")
                for(var i=1;i<=10;i++){
                    document.write("<tr><td>"+i+"</td><td>"+factorial(i)+"</td></tr>")
                }   
                document.write("</table>")
                document.write( new Date()) 
            </script>
        </html>
    

    document.write()方法是其中一个由Netscape 2浏览器实现非常早起的脚本化API(脚本化后期提),它曾在DOM 之前就被很好的引入了,也曾是在文档中显示计算后的文本唯一的方法。简单一点总结就是,只有在解析文档时才能使用write()方法输出到HTML到当前文档中,如果将它放在函数定义或者事件程序调用,它就会擦除该文档所有内容,先于DOM树构建完成之前执行(可以这么理解)

      <h1 onclick='write()'>Table of Function</h1>
    
        </body>
            <script>
                function write(){
                    document.write('<h1>666</h1>')  //不管里面写什么,点击将清空所有内容
                }
            </script>
    

    当HTML解析器遇到script元素时,默认先执行脚本(圈起来),然后再恢复文档的解析和渲染。这对于内联的JavaScript没有什么问题,但如果脚本源代码是由一个src指定的外部文件,这意味着脚本后面的文档部分在下载和执行脚本之前,都不会出现在浏览器中(src与url的区别小伙伴可百度一下),这里是指文档的文本内容已经截入,但没有浏览器引擎解析成DOM树,DOM树的生成是受JavaScript代码执行影响的,JavaScript会“阻塞”页面UI的渲染。

    简单演示一下

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
        </head>
        <body>
            <h2>666</h2>
            <script>
              while(true){
            }
            </script>
            <h1>666</h1>
        </body>
        </html>
    

    在前面提过,DOM树的生成是受JavaScript代码执行影响的,我在上方定义了一个死循环,此时内容已经截入,但DOM树未解析成,因此我们看不到浏览器中有内容

    Script标签有两个属性,defer 和 async,两个属性都是不允许操作write()方法,也不能说不允许,可以说不执行,必须配合src使用,也就是说必须是引入外部脚本文件的时候使用,两者都存在以async效果为先。两个属性相当于告知了浏览器链接进来的脚本不会使用document.write()方法,也不会生成文档内容,因此浏览器在下载脚本时继续解析和渲染文档,区别在于async是异步操作。此处就不测试引入的document.write(),加defer 与async都是不予执行的

    简单做个比较,其实用的也不多,想深入可以再百度一下
    在外部编写一个js文件

        while(true){
              
        }
    

    在HTML中引入

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
        </head>
        <body>
            <h2>666</h2>
            <script defer src="./test.js">
                        
                </script>
            <h1>666</h1>
        </body>
       
        </html>
    

    DOM树还是无法解析

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
        </head>
        <body>
            <h2>666</h2>
            <script async src="./test.js"> 
                        //此处换属性了
                </script>
            <h1>666</h1>
        </body> 
        </html>
    

    此时DOM树已经解析完成,浏览器有元素

    今天内容差不多到这,很多东西也没有整理,比如说浏览器的同源策略,兼容与互用,安全与可访问 ,浏览器的测试原生AJAX,接下去想到啥写啥(^ _ ^)

    简单介绍一下浏览器解析代码的流程,如有错请指出

    区分进程和线程

    最常见进程就是我们的任务管理器吧,打开任务管理器就能看到一系列的进程,而且可以看到每个进程的内存资源信息以及cpu占有率

    进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)

    线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)

    浏览器是多进程的

    浏览器是多进程的

    浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存)

    简单点理解,每打开一个Tab页,就相当于创建了一个独立的浏览器进程。

    重点是浏览器内核(渲染进程)

    可以这样理解,页面的渲染,JS的执行,事件的循环,都在这个进程内进行。接下来重点分析这个进程(不提其他的,怕多说多错,自己了解的也不是很透彻)

    1.GUI渲染线程

    负责渲染浏览器界面,解析HTML,CSS,构建DOM树

    注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。如果JS引擎出问题(比如死循环,报错)导致DOM无法继续渲染

    2.JS引擎线程

    也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)

    JS引擎线程负责解析Javascript脚本,运行代码。

    JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序

    同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。

    JS阻塞页面加载
    从上述的互斥关系,可以推导出,JS如果执行时间过长就会阻塞页面。
    譬如,假设JS引擎正在进行巨量的计算,此时就算GUI有更新,也会被保存到队列中,等待JS引擎空闲后执行。
    然后,由于巨量计算,所以JS引擎很可能很久很久后才能空闲,自然会感觉到巨卡无比。
    所以,要尽量避免JS执行时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

    浏览器器内核拿到内容后,渲染大概可以划分成以下几个步骤:

    解析html建立dom树

    解析css构建render树(将CSS代码解析成树形的数据结构,然后结合DOM合并成render树)

    布局render树,负责各元素尺寸、位置的计算

    绘制render树(paint),绘制页面像素信息

    浏览器会将各层的信息发送给GPU,GPU会将各层合成(composite),显示在屏幕上。

    所有详细步骤都已经略去,渲染完毕后就是load事件了,之后就是自己的JS逻辑处理了

    初步解析,看不懂没关系 能理解最好,根据我前面提的机制应该稍微更能理解吧

    相关文章

      网友评论

          本文标题:客户端的JavaScript(一)

          本文链接:https://www.haomeiwen.com/subject/vziecqtx.html