整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

CSS是如何运行的?深入了解运行原理

SS是如何运行的?他到底是怎么工作的,如何从CSS应用到DOM,今天和大家分享下!

为什么学习

知识分类

基础计算机知识、基础软件安装、简单文件知识、HTML基础知识

目 标

理解浏览器如何加载CSS和HTML、浏览器遇到无法解析的CSS会发生什么

原 因

在一些面试场合,也会因为CSS原理会问到

CSS到底是怎么工作的?

当设备一个文件的时候,必须符合文件的内容文件的样式信息,下面我们会处理它的标准文件的样式信息,是,下面的步骤是加载网页的需要浏览的版本,展示它的版本。浏览器并且在处理文件的时候会有不同的方式,但是下面的步骤基本都会出现。

  1. 浏览器载入HTML文件(比如从网络上获取)。
  2. 将HTML文件转换成一个DOM(Document Object Model),DOM是文件在计算机内存中的表现形式,下一节将详细解释DOM。
  3. 会拉取该播放的资源,包含HTMLCSS相关的样式。播放JavaScript图片的播放器,然后在此进行处理,简单的同时对如何处理这个节JavaScript不会展开叙述。
  4. 浏览器拉取到CSS之后会进行解析,根据选择器的不同类型(如element、class、id等)把它们分到不同的“桶”中。浏览器根据它找到不同的选择器,将中间的不同规则(基于选择器的规则,如元素器、类选择器、id器等)应用在DOM的节点中,并添加不同依赖的样式(这个步骤称为渲染树)。
  5. 之前的结构进行了预测,之后渲染树应该会出现。
  6. 网页展示在屏幕上(这一步被称为着色)。

结合下面的图示更形象:

关于DOM

一个DOM有一个树形文字结构,标注语言中的每个元素、属性以及每一段都着结构树中的节点(Node/DOM或DOM node)。节点由一个节点本身和其他DOM节点的关系定义,有些有父节点,有些节点有兄弟节点(同级)。

对于DOM的理解操作会帮助你设计、调试和维护你的CSS,因为DOM是你的CSS样式和文件内容的部分。当你浏览器F12调试的时候你需要DOM以查看使用了哪些规则。

一个真实的DOM案例

很长且枯燥的案例,这里我们通过一个HTML片段来了解HTML如何转换成DOM

下面列HTML代码:当前

在这个 DOM 中,<p>元素的节点是父节点,它的子节点是一个文本节点和三个节点节点<span>的节点节点,SPAN同时也是他们的文本节点的父节点。

上图就是浏览器怎么解析之前的那个HTML片段——它生成上图的DOM树形结构,然后按照输出到浏览器:


应用CSS到DOM

让我们看看添加一些CSS到文件里渲染,同样的HTML代码:

下面为CSS代码:

浏览器会解析HTML并创建一个DOM,然后解析CSS。可以看到唯一的选择器就是span元素选择器,浏览器处理规则会非常快!把同样的规则用在三个<span>标签上,然后直接渲染出图像到屏幕上。

现在的显示如下:


当浏览器遇到无法解析的CSS代码会发生什么

在的文章中提到了并不会实现所有的浏览器,很多人也不会实现最新的浏览器的文章,因此我们可以同时使用 CSS 持续不断地开发之前的领先浏览器,你可能会宣布奇怪的选择器遇到无法解析的 CSS 器或何时会发生浏览?

答案就是浏览器什么也不会做,继续解析下一个CSS样式!

如果这些浏览器在解析你所写的 CSS 规则制定的过程中遇到了无法理解的属性或值,它会显示并继续解析 CSS 声明。或者当浏览器遇到它很新的时候还没有支持的 CSS 代码的时候上面的情况同样会发生(触发)。

类似的,当遇到无法解析选择器的时间时,他会直接启动整个选择器规则,解析下一个 CSS 选择器。

下面的案例中,我使用会导致错误的英式拼写来写“颜色”,所以我的属性的段落没有被渲染成蓝色,而执行其他的CSS代码会正常,只有错误的部分会被触发。



浏览器浏览中多,代表着你使用最新的 CSS 优化过程中的一个无法解析的规则也不会报错。当你浏览多个 CSS 样式的时候,会加载样式表中指定的元素最后的 CSS 代码进行渲染多个样式表,上级请同一个指定的样式表,正因为这样,你来解决一些浏览器等浏览器也不能为新特性的问题(比如指定两个 CSS 样式)个width)。

这个特点在你想的一个很新的 CSS 特性,但不是所有的浏览器都支持使用的时候(浏览器)非常有用,更有意义,一些老的浏览器不接受calc()(计算一下,CSS3 新增,作为元素动态宽度、长度等,注意指定这里的动态是计算的一个值)。就这样;新式的浏览器指定并把一个行解析成图片,覆盖第一行的丰富内容。

后面的课程我们会讨论更多关于浏览器的连接问题。

最后

恭喜你完成本模块,下面的文章你用你的新知识来完成覆盖样式的案例,在这个过程中测试一些 CSS 样式。

理解JavaScript运行原理,我们需要理解以下两方面内容。

  • JavaScript引擎。
  • JavaScript运行时环境。

什么是JavaScript引擎

JavaScript引擎是一个计算机程序,它的主要作用是JavaScript运行时将源码编译为机器码。

每个主流Web浏览器都有自己的JavaScript引擎,它通常由web浏览器供应商开发。

主流web浏览器

  • Google Chrome V8。
  • Mozilla Firefox Spider Monkey。
  • Safari Javascript Core Webkit。
  • Edge (Internet Explorer)

以前的JavaScript引擎主要在web浏览器使用,不过随着nodejs的出现就打破了这种局限。

V8引擎

V8包含了解析器(parser),解释器(Ignition),优化编译器(TurboFan )。

解析器(parser):用于生成抽象语法树。

JavaScript代码的句法结构的树形表示形式

解释器(Ignition):将源码转换为字节码。

解释器

优化编译器(TurboFan ):进行一些优化编译优化处理,比如内联缓存。

下面是V8引擎的大体工作流程。

  1. 首先解析器先生成一个抽象语法树。
  2. 然后解释器根据语法树生成V8格式的字节码。
  3. 优化编译器再将字节码编译成机器码。

源码转化为机器码流程

运行时环境

浏览器运行环境中,浏览器提供了Web API,如:HTTP请求,计时器,事件等。

服务器运行环境中,nodejs提供了API。

下面是JavaScript在浏览器中运行时的架构,它包含一个内存堆、一个内存栈、一个事件循环、一个回调队列。

JavaScript运行时架构

  • 内存栈(stack),一个连续的内存区域,为每个执行的函数分配本地上下文。
  • 内存堆( heap), 一个更大的内存区域,存储动态分配的所有内容。
  • 调用栈(call stack), 一种数据结构,记录了我们在程序中的位置。
  • 回调队列(callback queue),存储异步任务的回调函数。
  • 事件循环(event loop),持续检查调用栈是否为空,如果为空,将回调队列中头部回调函数移动到调用栈执行。

运行时的调用栈

下面代码展示了JavaScript执行的调用栈变化。

JavaScript调用栈

function add(x, y) {
    return x + y;
}

function print(x, y) {
    console.log('x+y=',add(x, y))
}

print(1, 3)

异步任务

JavaScript先执行了print函数,然后调用Web API setTimeout(),Web API存储了setTimeout() 的回调函数,3秒后将回调函数添加到回调队列,事件循环发现调用栈为空,于是将队列里的回调函数移至调用栈执行。

异步任务

function add(x, y) {
    return x + y;
}

function print(x, y) {
    setTimeout(function (){
        console.log('x+y=',add(x, y))
    }, 3000)
}

print(1, 3)

小结

JavaScript运行主要依靠JavaScript引擎和运行环境,引擎将js源码翻译成计算机所理解的机器码,运行环境提供了一些与计算机底层通讯的API和运行实现。

者:Lydia Hallie
译者:前端小智
来源:dev


JavaScript 很酷,但是 JS 引擎是如何才能理解我们编写的代码呢?作为 JS 开发人员,我们通常不需要自己处理编译器。然而,了解 JS 引擎的基础知识并了解它如何处理JS代码,并将其转换成机器能够理解的东西,绝对是个有益无害的事情。

注意:本文主要基于 Node.js 和基于 Chrome 的浏览器使用的 V8 引擎。

HTML解析器遇到带有源代码的script标签。来自此源的代码从网络,缓存或已安装的服务工作程序中加载。响应是将请求的脚本作为字节流,由字节流解码器负责。字节流解码器在下载字节流时对其进行解码。

字节流解码器从已解码的字节流中创建令牌。例如,0066解码为f, 0075到u,006e到n, 0063到c, 0074到t, 0069到i, 006f到o, 006e到n,后面跟一个空格。就像JS中的function,这是 JS 中的一个保留关键字,它会创建一个标记,并将其发送给解析器。对于字节流的其余部分也是如此。

该引擎使用两个解析器:预解析器(pre-parser)解析器(parser)。预解析器只提前检查标记,以查看是否有语法错误。这可以减少发现代码中的错误所需的时间,否则解析器稍后就会发现这些错误。

如果没有错误,解析器将根据从字节流解码器接收到的标记创建节点。使用这些节点,它创建了一个抽象语法树,即AST

接下来,轮到解释器(interpreter)了。遍历AST并根据AST包含的信息生成字节码的解释器。一旦字节码完全生成,AST就会被删除,从而清除内存空间。最后,生成的机器码就可以在电脑上运行了。

虽然字节码很快,但它可以更快。当这个字节码运行时,将生成信息。它可以检测某些行为是否经常发生,以及所使用数据的类型。也许已经调用一个函数几十次了:现在是时候优化它了,这样它会运行得更快!

字节码与生成的类型反馈一起发送到优化编译器(ptimizing compiler)。优化的编译器接收字节码和类型反馈,并根据这些信息生成高度优化的机器码。

JS 是一种动态类型语言,这意味着数据类型可以不断变化。如果 JS引擎每次都要检查某个值的数据类型,那么速度会非常慢。

相反,JS 引擎使用一种称为内联缓存(inline caching)的技术。它将代码缓存在内存中,希望将来它会以相同的行为返回相同的值.假设某个函数被调用100次,并且到目前为止总是返回相同的值。它将假设在第101次调用它时也会返回这个值。

假设我们有以下函数sum,(到目前为止)每次都使用数值作为参数来调用它:

ffunction sum(a, b){
  return a + b
}
sum(1, 2

执行结果为 3。下次调用它时,它将假定我们再次使用两个相同数字对其进行调用。

如果假投,那么就不需要动态查找,只需要使用存储在特定内存槽中的结果,该槽已经有一个引用。否则,如果假设不正确,它将反优化代码并恢复到原始字节码,而不是优化后的机器码。

例如,下一次调用它时,我们传递的是字符串而不是数字。因为 JS 是动态类型的,所以这样做不会有任何错误。

function sum(a, b){
  return a + b
}
sum('1', 2)

这意味着数字2将被强制转换成字符串,而函数将返回字符串'12'。它返回执行解释的字节码并更新类型反馈。

我希望这篇文章对你有用!当然,在这篇文章中还没有涉及到引擎的更多部分(JS堆,调用堆栈,等等),后续会继续分享。如果你对 JS 的内部机制感兴趣,强烈建议自己可以做一些研究,V8 是开源的,并且有一些很棒的文档说明它是如何工作的。


https://dev.to/lydiahallie/javascript-visualized-the-javascript-engine-4cdf