美文网首页面试相关
前端知识梳理-浏览器篇

前端知识梳理-浏览器篇

作者: 变量只提升声明不提升赋值 | 来源:发表于2023-02-20 21:08 被阅读0次

    一、什么是进程,什么是线程

    进程是cpu资源分配最小单位,线程是进程最小调度单位。 在我们的操作系统中,有许多许多的进程,操作系统每干一件事儿就会交给一个进程去做,比如打开音乐就是一个进程。而每个进程里又包含了许多的线程,例如打开了音乐播放器,放一首歌,就是一个新的线程,切换下一首,可能又是另外一个线程。总之他俩之间的关系就是一个进程包含多个线程。

    二、浏览器是多进程还是单进程

    浏览器一般都是多进程,每开一个tab页,就是一个新的进程。这也就是为什么一个tab页崩溃了不会影响到整个浏览器崩溃。他主要分为以下几个进程:
    1、主进程:只有一个,负责调度主控整个浏览器
    2、插件进程:每个插件都有一个进程,只在插件被调用的时候创建
    3、GPU进程:只有一个,负责3d绘制
    4、渲染进程:每个tab页一个,负责网页的渲染,脚本的执行和事件的处理等。这个进程也是前端最需要了解的进程。

    三、渲染进程

    要了解渲染进程,那就得从他有几个线程开始。
    渲染进程主要有以下几个线程:
    1、GUI线程:负责页面的构建和渲染,当页面需要被绘制的时候就会启动这个线程,要注意的是,他和js引擎线程是互斥的,不能并行执行
    2、js引擎线程:负责解析和执行js脚本,因为他和GUI线程的互斥性,所以js代码是会导致页面渲染不连贯的,也就是常说的阻塞页面渲染
    3、事件触发线程:归属于浏览器,而不是js引擎,他主要就是控制事件循环,将一系列的任务加入一个队列等js引擎空闲下来后去执行
    4、定时器线程:管理定时器的计时,等时间到了就把事件推入任务队列,等待js引擎执行
    5、异步http请求线程:每发送一个请求就会开启一个新的线程,等待响应后把回调函数推入任务队列,等js引擎执行。

    以上几个就是渲染进程的主要线程。其实通过上述的了解我们就可以大概明白了,js的代码执行顺序为什么是那样,可以简单的认为只有同步代码是第一时间就在js引擎线程里去执行的,其他的例如宏任务,微任务,等都是由别的线程管理,当满足条件后才将代码交给js引擎去执行。

    那接下来就聊一聊老生常谈的浏览器渲染流程:

    1、首先浏览器会去解析html文件,构建DOM树,然后解析css,生成css树。
    2、等DOM树和css树都构建好了之后,会将两者合并,生成最终的render树
    3、接着去布局render树,计算位置 尺寸。然后再绘制render树。
    4、最后将各层的信息发送给GPU,GPU合成渲染层最终呈现出页面。

    在浏览器的渲染过程中还有两个钩子会被触发,他们就是load事件和DOMcontentloaded事件
    那二者有什么区别呢?
    DOMcontentloaded事件会在dom树构建完成之后(不包括样式表,图片等)就执行,而load事件会在渲染完毕后被执行。所有前者是先于后者执行的

    下一个问题,css到底会不会阻塞dom渲染呢?

    首先看一下浏览器的渲染流程图


    image.png

    可以看到,DOM的加载和css的加载时并行执行的,所以理论上来说css是不会阻塞dom渲染的,但是最终的渲染是需要dom树和css树共同生成一个render树,就算dom树构建好了,但是css树没构建好,那也没办法渲染页面。所以css的加载不会阻塞但是css的解析又是会阻塞页面渲染的。

    浏览器的回流和重绘:

    回流指的时当元素发生大小位置上的变化,引起整个结构也变化了这个时候浏览器就会触发回流,重绘则是元素的颜色背景色等不影响布局变化的地方发生了变化,就会触发重绘。

    回流一定触发重绘,但重绘不一定触发回流。

    那平时应该怎么尽量避免这两个问题呢?
    1、尽量把操作dom的过程统一执行,以减少回流重绘的次数
    2、把需要多次操作的dom先display:none,操作完在展示出来
    3、使带有动画的dom脱离文档流
    4、尽量使用偏移量transform去代替left top等位移属性
    5、使用一些能触发GPU加速的样式代替原来的写法

    script标签

    说完了html,css,当然还要聊一聊最重要的js环节了。
    看完上面这些内容我们大概已经知道了,js为什么会阻塞页面渲染,那有没有什么办法避免呢。
    首先了解以下script标签上的async和defer两个属性

    async:异步加载js文件,他会在异步加载完成之后立即执行js文件,所以还是会阻塞后续的dom渲染。
    defer:也是异步加载,他和async不同的是,他加载完成之后不会立即执行,而是会等到DOM树构建完毕DOMcontentloaded执行之前再去执行脚本。

    并且因为async加载就执行的特点,导致async加载js文件时无序的,这可能会出现当某个js需要依赖上一个js的时候,上一个js还没加载过来的问题。而defer则时有序的执行js,会按照你书写的script标签顺序去执行。

    好啦,了解完这么多,应该就明白了为什么通常js要放在页面的底部引入。只要记住GUI渲染线程和js线程是互斥的就能回答大部分阻塞的问题了

    相关文章

      网友评论

        本文标题:前端知识梳理-浏览器篇

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