浏览器渲染机制和node事件循环

浏览器渲染机制

Document Object Model (DOM)

当浏览器读取 HTML 代码时,只要遇到 body、div 等 HTML 元素,就会创建一个名为 Node 的 JavaScript 对象。

浏览器从 HTML 文档中创建了 Node 之后,就要把这些节点对象创建成树状结构。

CSS Object Model (CSSOM)

是一种用于描述和操作CSS样式表的模型。它将CSS样式表表示为一个对象树,每个对象代表样式表中的一个规则或者样式信息。CSSOM 允许开发人员通过编程方式读取和操作CSS样式表,包括修改样式规则、查询元素的计算样式等。

在W3C标准中,它包含两个部分:描述样式表和规则等CSS的模型部分(CSSOM),和跟元素视图相关的View部分(CSSOM View)。

他提供了一些api包括:
规则部分,支持对元素属性的修改

document.styleSheets[0].insertRule("p { color:pink; }", 0)
document.styleSheets[0].removeRule(0)


视图部分
窗口 API

窗口API用于操作浏览器窗口的位置、尺寸等

  1. moveTo(x, y) 窗口移动到屏幕的特定坐标;
滚动 API

视口滚动API

scrollX 是视口的属性,表示X方向上的当前滚动距离

元素滚动API

scrollTop 元素的属性,表示Y方向上的当前滚动距离。

布局API

这是整个CSSOM中最常用到的部分,我们同样要分成全局API和元素上的API。

全局尺寸信息

如window.innerHeight, window.innerWidth 这两个属性表示视口的大小。

元素的布局信息

所以我们获取宽高的对象应该是“盒”,于是CSSOM View为Element类添加了两个方法:

  1. getClientRects();会返回一个列表,里面包含元素对应的每一个盒所占据的客户端矩形区域,这里每一个矩形区域可以用 x, y, width, height 来获取它的位置和尺寸。
  2. getBoundingClientRect()。

Render Tree

Render-Tree 也是一个将 DOM 树和 CSSOM 树组合在一起构建的树状结构。

渲染顺序

布局操作

首先浏览器创建每个单独的 Render-Tree 节点的布局。布局包括每个节点的大小(以像素为单位)和它将被打印在屏幕上的位置。这个过程被称为布局,因为浏览器正在计算每个节点的布局信息

绘制操作

由于 Render-Tree 中的元素(或子树)可以相互重叠,而且它们可以具有 CSS 属性,使它们经常改变外观、位置或几何显示(如动画),因此浏览器会为它创建一个图层

创建图层可以帮助浏览器在网页的整个生命周期中高效地执行绘制操作,比如在滚动或调整浏览器窗口大小的时候。拥有图层还可以帮助浏览器按照开发者的意图,正确地按照堆叠顺序(沿 z 轴)绘制元素。

现在我们有了图层,我们可以将它们组合起来,并在屏幕上绘制。但是浏览器并不是一次性绘制所有的图层。每个图层都是先单独绘制的

在每个图层里面,浏览器会对元素的任何可见属性,如边框、背景色、阴影、文字等进行单独的像素填充。

合成操作

我们拥有的是不同的图层(位图图像),它们应该按照特定的顺序绘制在屏幕上。在合成操作中,这些图层会被发送到 GPU 上,最终将其绘制在屏幕上。

每次回流(布局)或重绘时都要将整个图层送去绘制,这显然是很低效的。因此,一个图层被分解成不同的块,然后将其绘制在屏幕上

细节

细节一:script会阻塞dom的解析

如果它是一个嵌入式 script,那么它将首先执行该 script,然后继续解析 HTML,构建 DOM 树。所以所有的嵌入式 script都是解析器阻塞型的

如果 script 元素是外部 script 文件,浏览器会在主线程之外开始下载外部 script 文件,但在该文件下载完毕之前,会停止主线程的执行。这意味着在 script 文件下载之前,不会再进行 DOM 解析。

async 属性,当 DOM 解析器遇到一个带有 async 属性的外部 script 元素时,它不会在后台下载 script 文件时停止解析过程。但是一旦文件下载完毕,解析过程就会停止,script(代码)就会被执行。

defer 属性,它的工作原理与 async 属性类似,但与 async 属性不同的是,即使文件完全下载完毕,script 也不会执行。一旦解析器解析了所有的 HTML,也就是说 DOM 树已经完全构建完成,所有的 defer script就会被执行。与async 不同的是,所有的延迟 script 是按照它们在 HTML 文档(或 DOM 树)中出现的顺序来执行的。

细节二:css会阻塞dom的解析

DOM 和 CSSOM 树的构建都发生在主线程上,而且这些树的构建是同时进行的。它们共同构成了用于在屏幕上打印东西的 Render Tree,而 Render Tree 也随着 DOM 树的构建而逐步构建。

我们已经了解到,DOM 树的生成是增量的,这意味着当浏览器读取 HTML 时,它会将 DOM 元素添加到 DOM 树中。但 CSSOM 树却不是这样。与 DOM 树不同,CSSOM 树的构建不是递增的,必须以特定的方式进行

因此,如果浏览器在解析样式表内容时开始递增地构建 CSSOM,就会导致渲染树的多次渲染,因为样式覆盖规则会使同样的 CSSOM 节点,因后面新出现的样式表文件而导致更新。当 CSS 被解析时,可以在屏幕上看到元素样式的改变,这将是一种不愉快的用户体验。由于 CSS 样式是层叠的,一个规则的改变可能会影响许多元素。

因此,浏览器不会逐步处理外部 CSS 文件,CSSOM 树更新是在样式表中所有 CSS 规则处理完毕后一次性完成的。CSSOM 树更新完成后,再更新渲染树,然后渲染到屏幕上。

CSS 是一种渲染阻塞型资源。一旦浏览器提出获取外部样式表的请求,Render Tree 的构建就会停止。因此,关键渲染路径(CRP)也被卡住了,没有任何东西被渲染到屏幕上,如下图所示。然而,在后台下载样式表时,DOM 树的构建仍在进行中。

但是一旦样式表被下载和解析,导致 CSSOM 更新,我们的 JavaScript 现在有一个过时的元素的 CSS 值,因为新的 CSSOM 更新可能已经改变了该 DOM 元素的 CSS 属性。由于这个原因,在下载样式表的时候执行 JavaScript 是不安全的

浏览器会等到样式表被加载和解析。一旦样式表被解析,CSSOM 被更新,Render Tree 就会被更新,CRP 就会继续进行,从而使 Render Tree 绘制在屏幕上。由于这个原因,建议尽早加载所有外部样式表

node的事件循环

浏览器中的事件循环是根据 HTML 标准实现的,而 Node.js 中的事件循环则是基于 libuv 实现的。

libuv 是一个用 C 语言实现的高性能解决单线程非阻塞异步 I/O 的开源库,本质上它是对常见操作系统底层异步 I/O 操作的封装。

而在 nodejs 中,这都是 libuv 完成的。

几乎每个 Node API 都有异步执行版本libuv 直接负责它们的执行,libuv 会开启一个线程池,主线程执行到异步操作后,libuv 就会在线程池中调度空闲线程去执行,可以说 libuv 为 nodejs 提供了整个事件循环功能。

过程

与在浏览器中一样,在 nodejs 中 JS 最开始在主线程上执行,执行同步任务、发出异步请求、规划定时器生效时间、执行 process.nextTick 等,这时事件循环还没开始。

在上述过程中,如果没有异步操作,代码在执行完成后便直接退出。如果有,libuv 会把不同的异步任务分配给不同的线程,形成事件循环。在同步代码执行完后,nodejs 便会进入事件循环,依次执行不同队列中的任务。

Nodejs 事件循环中的消息队列共有 8 个,若引用之前宏队列、微队列的说法,具体可划分为:

  • 宏队列
    • timers (重要),计时器队列,负责处理 setTimeout 和 setInterval 定义的回调函数。
    • pending callback (待定回调)
      • 调用上一次事件循环没在 poll 阶段立刻执行,而延迟的 I/O 回调函数
    • idle prepare (空闲准备)
      • 仅供 nodejs 内部使用
    • poll (重要),轮询队列,该阶段会处理除 timers 和 check 队列外的绝大多数 I/O 回调任务,如文件读取、监听用户请求等。
    • check (重要),检查队列,负责处理 setImmediate 定义的回调函数。
    • close callbacks
      • 执行所有注册 close 事件的回调函数
  • 微队列
    • nextTick
    • Promise

对于微队列的 nextTick 和 Promise,严格意义上讲也不属于事件循环。在事件循环中,每次打算进入下个阶段之前,必须要先依次反复清空 nextTick 和 promise 队列,直到两个队列完全没有即将要到来的任务的时候再进入下个阶段。

node高并发机制

 事件驱动+事件循环实现高并发

执行顺序:

1、每个Node.js进程只有一个主线程在执行程序代码,形成一个执行栈(execution context stack)

2、主线程之外,还维护了一个"事件队列"(Event queue)。当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。

3、主线程代码执行完毕完成后,然后通过Event Loop,也就是事件循环机制,开始到Event Queue的开头取出第一个事件,从线程池中分配一个线程去执行这个事件,接下来继续取出第二个事件,再从线程池中分配一个线程去执行,然后第三个,第四个。主线程不断的检查事件队列中是否有未执行的事件,直到事件队列中所有事件都执行完了,此后每当有新的事件加入到事件队列中,都会通知主线程按顺序取出交EventLoop处理。当有事件执行完毕后,会通知主线程,主线程执行回调,线程归还给线程池。

注意

我们所看到的node.js单线程只是一个js主线程与ui渲染共享一个线程,本质上的异步操作还是由线程池完成的,node将所有的阻塞操作都交给了内部的线程池去实现,本身只负责不断的往返调度,并没有进行真正的I/O操作,从而实现异步非阻塞I/O,这便是node单线程和事件驱动的精髓之处了。

总结:

1、libuv 线程池默认打开 4 个,最多打开 128个 线程。(例如:以前 web 服务器同一时间比如说最多只能接收 100 个请求,多的就无法接收了,服务器就挂掉了。nodejs 所谓的高并发是指可以同时接收 1000、10000 个请求,只不过以排队的方式在等待。

2、主线程执行js,是单线程的,js代码在做大量计算就是cpu密集了。主线程不空闲出来也没法处理 io 的事,所以就会阻塞了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3266252.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

如何从2D到3D动画(计算机图形学基础)

引言 计算机图形学是一门将数学、计算机科学和艺术结合起来的学科,它在现代技术中扮演着越来越重要的角色。从游戏设计到虚拟现实(VR)、增强现实(AR)和元宇宙,计算机图形学的应用无处不在。它不仅为人们提…

godot新建项目及设置外部编辑器为vscode

一、新建项目 初次打开界面如下所示,点击取消按钮先关闭掉默认弹出的框 点击①新建弹出中间的弹窗②中填入项目的名称 ③中设置项目的存储路径,点击箭头所指浏览按钮,会弹出如下所示窗口 根据图中所示可以选择或新建自己的游戏存储路径&…

基于多种机器学习的豆瓣电影评分预测与多维度可视化【可加系统】

有需要本项目的代码或文档以及全部资源,或者部署调试可以私信博主 在本研究中,我们采用Python编程语言,利用爬虫技术实时获取豆瓣电影最新数据。通过分析豆瓣网站的结构,我们设计了一套有效的策略来爬取电影相关的JSON格式数据。…

JavaScript——变量与运算符、输入输出、判断、循环

文章目录 前言概述使用 js从文件引入 js 代码importjs 的作用变量计算输入格式化输出保留小数向上取整,向下取整条件判断循环总结 前言 为了监督自己的进度,把学习任务一点点都写出来,写多少就算多少,不求完美,只求完…

# JVM 参数大全

JVM 参数大全 文章目录 JVM 参数大全内存参数垃圾收集器配置GC日志配置dump 日志参数配置发生Full GC时生成dump文件在IDEA中配置JVM参数 内存参数 -Xmx3550m:设置JVM最大堆内存为3550M -Xms3550m:设置JVM初始堆内存 为3550M。此值可以设置与-Xmx相同&am…

【Python实战因果推断】57_因果推理概论7

目录 The Bias Equation A Visual Guide to Bias The Bias Equation 既然你现在理解了为何样本平均值可能与它试图估计的平均潜在结果存在差异,我们不妨更详细地探究为什么平均差值通常无法恢复出ATE(平均处理效应)。 在销售的例子中&…

linux ftp操作记录

一.ftp 创建用户 passwd: user ftpuser does not exist 如果你遇到 passwd: user ftpuser does not exist 的错误,这意味着系统中不存在名为 ftpuser 的用户。你需要首先确认FTP用户是否是系统用户,还是FTP服务器软件(如Pure-FTPd&#xff…

DATEDIFF()- Date Functions-SQL函数

DATEDIFF()- Date Functions DATEDIFF() 函数是一种用于计算日期差异的常见日期函数。 通常用于比较两个日期之间的时间跨度,以便进行日期计算和分析。 语法 大多数数据库中,DATEDIFF() 函数的语法: DATEDIFF(unit,…

力扣141环形链表问题|快慢指针算法详细推理,判断链表是否有环|龟兔赛跑算法

做题链接 目录 前言: 一、算法推导: 1.假设有环并且一定会相遇,那么一定是在环内相遇,且是快指针追上慢指针。 2.有环就一定会相遇吗?快指针是每次跳两步,有没有可能把慢指针跳过去? 3.那一定…

108页PPT麦肯锡--以价值为导向的企业战略规划

以价值为导向的企业战略规划 企业的高层管理者,受股东和其他权益所有者的委托,充当价值管理者的角色。高层经理对于企业进行战略规划的过程,也就是通过价值管理,创造价值的过程 战略规划应首先从挖掘具体业务的价值驱动因素着手…

【重要】23集 搭建ESP-IDF和VSCODE开发环境 编译Helloword和AI聊天工程-《MCU嵌入式AI开发笔记》

【重要】23集 搭建ESP-IDF和VSCODE开发环境 编译Helloword和AI聊天工程-《MCU嵌入式AI开发笔记》 参考文档: https://lceda001.feishu.cn/wiki/Xqx3wH8wMi3BrrkmeTXcgLL7nQk 我们修改了secretkey等,之后我们修改menuconfig 配置menuconfig 之后出现问题…

【轨物方案】成套开关柜在线监测物联网解决方案

随着物联网技术的发展,电力设备状态监测技术也得到了迅速发展。传统的电力成套开关柜设备状态监测方法主要采用人工巡检和定期维护的方式,这种方法不仅效率低下,而且难以保证设备的实时性和安全性。因此,基于物联网技术的成套开关…

ECharts实现按月统计和MTBF统计

一、数据准备 下表是小明最近一年的旅游记录 create_datecity_namecost_money2023-10-10 10:10:10北京14992023-11-11 11:11:11上海29992023-12-12 12:12:12上海19992024-01-24 12:12:12北京1232024-01-24 12:12:12上海2232024-02-24 12:12:12广州5642024-02-24 12:12:12北京…

【Jupyter Notebook】一文详细向您介绍 【重启内核】

【Jupyter Notebook】一文详细向您介绍 【重启内核】 下滑即可查看博客内容 🌈 欢迎莅临我的个人主页 👈这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地!🎇 🎓 博主简介:985高校的普通本硕…

基于Golang+Vue3快速搭建的博客系统

WANLI 博客系统 项目介绍 基于vue3和gin框架开发的前后端分离个人博客系统,包含md格式的文本编辑展示,点赞评论收藏,新闻热点,匿名聊天室,文章搜索等功能。 项目在线访问:http://bloggo.chat/ 或 http:/…

深入搞懂Checkpoint调优基础及原理

前言 在执行大量写操作的系统上,调优检查点对于获得良好的性能至关重要。然而,检查点是我们经常发现混淆和配置问题的地方之一,无论是在社区邮件列表中,还是在为客户提供支持和咨询期间。这篇文章旨在解释检查点是什么——目的和数据库如何实现它——以及如何调优它们。 注…

chapter08-面相对象编程的三大特征——封装

1、基础介绍 对电视机的操作就是典型封装 封装的好处:隐藏实现细节;可以对数据进行验证 2、封装的实现 3、入门案例 altinsert,getter and setter,自动插入

Docker(十)-Docker运行elasticsearch7.4.2容器实例

1.下载镜像 1.1存储和检索数据 docker pull elasticsearch:7.4.2 1.2可视化检索数据 docker pull kibana:7.4.22.创建elasticsearch实例 创建本地挂载数据卷配置目录 mkdir -p /software/elasticsearch/config 创建本地挂载数据卷数据目录 mkdir -p /software/elasticse…

Linux——管理本地用户和组(详细介绍了Linux中用户和组的概念及用法)

目录 一、用户和组概念 (一)、用户的概念 (二)、组的概念 补充组 主要组 二、获取超级用户访问权限 (一)、su 命令和su -命令 ( 二)、sudo命令 三、管理本地用户账户 &…

PyTorch模型训练步步详解:从零开始构建深度学习流程

P y T o r c h 训练模型流程图 PyTorch训练模型流程图 P y T orc h 训练模型流程图