浏览器工作原理与实践

01 | Chrome架构:仅仅打开了1个页面,为什么有4个进程?

  • 渲染 io 插件 网络 等等

02 | TCP协议:如何保证页面文件能被完整送达浏览器?

  • 计算机网络, 数据先tcp再ip

03 | HTTP请求流程:为什么很多站点第二次打开速度会很快?

在这里插入图片描述

在这里插入图片描述

04 | 导航流程:从输入URL到页面展示,这中间发生了什么?

  • 经典面试题: 加上浏览器渲染过程, 缓存, 后端架构(组成一个完美答案)

05 | 渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的?

  • 这是因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树。
  • 把 CSS 转换为浏览器能够理解的结构
  • 当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构——styleSheets。
  • 转换样式表中的属性值,使其标准化
  • 创建布局树
  • css属性会继承

06 | 渲染流程(下):HTML、CSS和JavaScript,是如何变成页面的?

  • z-index分层结构
  • 通常一个页面可能很大,但是用户只能看到其中的一部分,我们把用户可以看到的这个部分叫做视口(viewport)

在这里插入图片描述

  • 一个完整的渲染流程大致可总结为如下:

渲染进程将 HTML 内容转换为能够读懂的DOM 树结构。
渲染引擎将 CSS 样式表转化为浏览器可以理解的styleSheets,计算出 DOM 节点的样式。
创建布局树,并计算元素的布局信息。
对布局树进行分层,并生成分层树。
为每个图层生成绘制列表,并将其提交到合成线程。
合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
合成线程发送绘制图块命令DrawQuad给浏览器进程。
浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。

07 | 变量提升:JavaScript代码是按顺序执行的吗?

  • 变量提升, 有个执行上下文的对象

  • 定义函数存储在堆中

  • 当函数被调用时, 会在变量对象中查找该函数

  • 编译过程是非常复杂的, 包括词法分析, 语法分析, 代码优化, 代码生成等

  • 下面代码会输出什么

function showName() {
    console.log('极客邦');
}
showName();
function showName() {
    console.log('极客时间');
}
showName(); 
  • 先是编译阶段,纪录函数到栈中, 纪录变量对象。再是执行阶段同样都是输出“极客时间”,后定义的会覆盖之前变量的值

  • 但是Python中不是这样, 这跟编译器的区别有关

08 | 调用栈:为什么JavaScript代码会出现栈溢出?

  • 调用栈就是用来管理函数调用关系的一种数据结构
  • 栈可以理解为一个胡同
  • 管理执行上下文的栈成为执行上下文栈又称调用栈
  • 程序的执行过程
var a = 2
function add(b,c){
  return b+c
}
function addAll(b,c){
var d = 10
result = add(b,c)
return  a+result+d
}
addAll(3,6)
  • 创建全局上下文, 并将其压入栈底

在这里插入图片描述

  • 先初始化变量后进入代码的执行阶段。赋值,将a赋值成为2
  • 然后调用addAll函数,js引擎会编译该函数, 并创建执行上下文,最后将该函数执行上下文压入栈中

在这里插入图片描述

  • 进入代码执行阶段, 将d赋值为10
  • 当执行到add()函数时还会创建执行上下文, 并压入栈

在这里插入图片描述

  • 当add()函数返回时,函数的执行上下文就会从栈顶弹出, 并将result的值设置成add()函数的返回值

在这里插入图片描述

  • 最后addAll执行并返回, 也会从栈顶弹出来,此时只剩下全局上下文了

在这里插入图片描述

  • 至此,整个JavaScript流程执行结束
  • 调用栈是JavaScript引擎追中函数执行的一个机制
  • call Stack就是调用栈信息
  • console.trace()可以输出函数的调用关系
  • 因为调用栈有大小,写递归的代码容易出现栈溢出, 就是函数的调用栈
  • 调用栈有两个指标, 最大栈容量和最大调用深度
  • 算法经典思想:循环消除尾递归

09 | 块级作用域:var缺陷以及为什么要引入let和const?

  • 为什么js会有变量提升?

作用域: 在ES6之前只有两种作用域: 全局作用域和函数作用域
全局作用域在代码中的任何地方都会被访问, 伴随这页面的生命周期
函数级作用域: 定义的变量或函数只能在函数内部被访问. 函数执行之后, 函数内部营地的变量会被销毁.
块级作用域在ES6之后被支持就是使用大括号包裹的代码, 判断语句, 循环都是块级作用域

  • 外部不能访问内部, 内部可以访问父节
  • 点的外部
  • js会优先执行当前执行上下文中的变量
  • let关键字是可以被修改的, const不可以被修改
  • Python中变量提升: 将函数的局部作用域的变量提升到全局
  • gloabal n n = 100
def run():
    global n

    n = 100


# 必须先执行才会创建变量n
run()
print(n)
  • 变量提升存在变量覆盖, 变量污染的缺陷, 使用块级作用域来解决
  • js中存在变量提升和函数提升, Python中并不存在, 只是从上到下执行代码
let myname = "极客时间";
{
  console.log(myname);
  let myname = "极客邦";
}
  • 上述代码运行时会报错, 变量只是创建时会被提升, 但是初始化并未提升

10 | 作用域链和闭包 :代码中出现相同的变量,JavaScript引擎是如何选择的?

function bar() {
    console.log(myName)
}
function foo() {
    var myName = " 极客邦 "
    bar()
}
var myName = " 极客时间 "
foo()

在这里插入图片描述

  • 作用域链: 每个执行上下文的变量环境中, 都包含一个外部引用, 用来指向外部上下文, 这个外部的引用称为outer
  • 当一段代码中使用了一个变量, js引擎会在当前的执行上下文查找该变量
    在这里插入图片描述
  • 两者的外部指向执行上下文都是全局执行上下文
  • Python中的闭包是因为函数是一等公民, 和go中类似了但是js中的闭包是返回一个对象, 都是返回一个对象, 对象里面有函数或者, 这个对象可以被调用, 执行里面的代码.
  • 闭包是如何销毁的, 垃圾回收器会判断
  • 作用域链是查找变量的路径
  • 词法环境用于存放let 和 const的内容

11 | this:从JavaScript执行上下文的视角讲清楚this

  • 每个执行上下文都会绑定一个this
  • 全局执行上下文的this指向window对象
  • 嵌套函数中的 this 不会继承外层函数的 this 值。
  • 可以用that = this或者使用箭头函数, 箭头函数 不会创建执行上下文
  • 里面的this就是外层函数的this
  • this就是该对象

12 | 栈空间和堆空间:数据是如何存储的?

  • js在运行过程中是如何存储数据的? js的内存模型

在这里插入图片描述

  • 栈空间就是调用栈, 存储执行上下文
  • 当存在引用类型, 就不存放在栈中, 而是存放地址, 指向堆, 堆中存储Object数据.值类型则保存在栈中, 因为栈空间有限, 存储太多内容会造成栈溢出

在这里插入图片描述

  • 堆空间很大, 能存放很多数据, 不过分配内存和回收内存都会占用一定的时间
  • 闭包: 内部函数引入了外部函数的变量
  • 原始类型和引用类型, Python都是引用类型, 但是分为可变对象和不可变对象

13 | 垃圾回收:垃圾数据是如何自动回收的?

  • 有的垃圾回收之后后会产生内存随便, 需要整理
  • v8引擎主垃圾回收器采用标记清除法但是会产生内存碎片, 优化是标记整理算法
  • 一旦执行垃圾回收算法,都需要将正在执行的 JavaScript 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。我们把这种行为叫做全停顿
  • 为了降低老生代的垃圾回收而造成的卡顿,V8 将标记过程分为一个个的子标记过程,同时让垃圾回收标记和 JavaScript 应用逻辑交替进行,直到标记阶段完成,我们把这个算法称为增量标记(Incremental Marking)算法
  • 使用增量标记算法,可以把一个完整的垃圾回收任务拆分为很多小的任务,这些小的任务执行时间比较短,可以穿插在其他的 JavaScript 任务中间执行,这样当执行上述动画效果时,就不会让用户因为垃圾回收任务而感受到页面的卡顿了。
  • v8引擎分为新生代和老生代

14 | 编译器和解释器:V8是如何执行一段JavaScript代码的?

  • 编译器和解释器
    在这里插入图片描述

  • v8是如何执行js的

在这里插入图片描述

  • 编译器和解释器只能理解AST: 抽象语法树, 类似于将HTML编译成DOM树
  • babel可以将es6转化成es5
  • ESLint也是通过AST
  • AST是怎么产生的: 先是分词(词法分析) parse:语法分析 语义分析
  • 生成字节码或二进制码

其实一开始 V8 并没有字节码,而是直接将 AST 转换为机器码,由于执行机器码的效率是非常高效的,所以这种方式在发布后的一段时间内运行效果是非常好的。但是随着 Chrome 在手机上的广泛普及,特别是运行在 512M 内存的手机上,内存占用问题也暴露出来了,因为 V8 需要消耗大量的内存来存放转换后的机器码。为了解决内存占用问题,V8 团队大幅重构了引擎架构,引入字节码,并且抛弃了之前的编译器,最终花了将进四年的时间,实现了现在的这套架构。

  • 字节码就是介于 AST 和机器码之间的一种代码。但是与特定类型的机器码无关,字节码需要通过解释器将其转换为机器码后才能执行。

在这里插入图片描述

  • 当出现了热点代码就是编译成机器码
  • 字节码配合解释器和编译器就是Java Python的虚拟机称为JIT技术

在这里插入图片描述

  • WebAssembly就像java先编译成字节码然后执行在虚拟机上.

15 | 消息队列和事件循环:页面是怎么“活”起来的?

在这里插入图片描述

在这里插入图片描述

  • 如何处理高优先级的任务?

  • 如果有一些确定好的任务,可以使用一个单线程来按照顺序处理这些任务,这是第一版线程模型。

  • 要在线程执行过程中接收并处理新的任务,就需要引入循环语句和事件系统,这是第二版线程模型。

  • 如果要接收其他线程发送过来的任务,就需要引入消息队列,这是第三版线程模型。

  • 如果其他进程想要发送任务给页面主线程,那么先通过 IPC 把任务发送给渲染进程的 IO 线程,IO 线程再把任务发送给页面主线程。

  • 消息队列机制并不是太灵活,为了适应效率和实时性,引入了微任务。

  • 宏任务是开会分配的工作内容,微任务是工作过程中被临时安排的内容

16 | WebAPI:setTimeout是如何实现的?

  • setTimeout是一个定时器,用来指定某个函数在多少毫秒之后执行。
  • 延时器最大为21.8天, 否则会立即执行

17 | WebAPI:XMLHttpRequest是怎么实现的?

  • 将一个函数作为参数传递给另一个函数, 这个函数就叫回调函数
  • XMLHttpRequest就是不用刷新整个界面只需要局部刷新就可以
  • 在主函数外部执行的过程叫异步回调

18 | 宏任务和微任务:不是所有任务都是一个待遇

  • Promise就是微任务
  • 宏任务: 渲染, 交互, js脚本
  • 为什么宏任务无法满足时间精度高的需求
  • 宏任务和微任务是绑定的
  • web应用要监控DOM变化, 是前端很重要的需求
  • mutation event采用了观察者模式
  • 异步+微任务(解决实时性问题) 微任务队列

19 | Promise:使用Promise,告别回调函数

  • 这一讲没听懂, 等以后心情好了再研究研究

20 | async/await:使用同步的方式去写异步代码

  • ES7引入了async/await
  • 一个线程可以存在多个协程, 但是线程上只能执行一个协程
  • 协程加时间循环

21 | Chrome开发者工具:利用网络面板做性能分析

-在这里插入图片描述

  • 浏览器会为每个域名最多维护 6 个 TCP 连接
  • TTFB: 第一字节时间
  • 排队时间过久,大概率是由浏览器为每个域名最多维护 6 个连接导致的。
  • 还建议你把站点升级到 HTTP2,因为 HTTP2 已经没有每个域名最多维护 6 个 TCP 连接的限制了。
  • 资源放在多个域名下面,比如放到 3 个域名下面,这样就可以同时支持 18 个连接了,这种方案称为域名分片技术。
  • 第一字节时间(TTFB)时间过久

22 | DOM树:JavaScript是如何影响DOM树构建的?

  • 渲染引擎无法理解HTML, 需要组成DOM树
  • js可以访问DOM
  • HTML Parser就是负责将HTML字节流转化为DOM结构
  • 字节流转化为DOM也都是通过编译技术

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 遇到js会进行下载

23 | 渲染流水线:CSS如何影响首次加载时的白屏时间?

  • css对页面的渲染也造成了影响

24 | 分层和合成机制:为什么CSS动画比JavaScript高效?

  • css动画比js动画更加高效

25 | 页面性能:如何系统地优化页面?

  • 通常 1 个 HTTP 的数据包在 14KB 左右
  • 内联css会减少资源请求数量
  • 减少 JavaScript 脚本执行时间

26 | 虚拟DOM:虚拟DOM和实际的DOM有何不同?

  • 两大著名前端框架 React 和 Vue 都使用了虚拟 DOM
  • 减少 JavaScript 对 DOM 的操作,这时候虚拟 DOM 就上场了。
  • 将页面改变的内容应用到虚拟 DOM 上,而不是直接应用到 DOM 上。
  • 变化被应用到虚拟 DOM 上时,虚拟 DOM 并不急着去渲染页面,而仅仅是调整虚拟 DOM 的内部状态,这样操作虚拟 DOM 的代价就变得非常轻了。
  • 在虚拟 DOM 收集到足够的改变时,再把这些变化一次性应用到真实的 DOM 上。
  • 在执行算法的过程中出让主线程yield
  • 虚拟 DOM 看成是 DOM 的一个 buffer
  • MVC核心思想就是将数据和视图分离

27 | 渐进式网页应用(PWA):它究竟解决了Web应用的哪些问题?

  • 第一个是应用程序 Web 化;
  • 第二个是 Web 应用移动化;
  • 第三个是 Web 操作系统化;
  • PWA渐进式网页应用
  • 渐进式 +Web 应用
  • Web 应用缺少离线使用能力,在离线或者在弱网环境下基本上是无法使用的
  • Web 应用还缺少了消息推送的能力,因为作为一个 App 厂商,需要有将消息送达到应用的能力。
  • Web 应用缺少一级入口,也就是将 Web 应用安装到桌面,在需要的时候直接从桌面打开 Web 应用,而不是每次都需要通过浏览器来打开。
  • Service Worker 来试着解决离线存储和消息推送的问题,通过引入 manifest.json 来解决一级入口的问题。
  • 为了避免 JavaScript 过多占用页面主线程时长的情况,浏览器实现了 Web Worker 的功能。Web Worker 的目的是让 JavaScript 能够运行在页面主线程之外,不过由于 Web Worker 中是没有当前页面的 DOM 环境的,所以在 Web Worker 中只能执行一些和 DOM 无关的 JavaScript 脚本

28 | WebComponent:像搭积木一样构建Web应用

  • 组件化思维

29 | HTTP/1:HTTP性能优化

  • content-encoding: br
  • content-type: text/html; charset=UTF-8
  • 服务器的响应信息
  • HTTP1.1提供了keep-alived, 使用CDN实现域名分片机制
  • HTTP1.1: 队头阻塞问题, 同一个域名6个链接, 请求头文本传输

30|HTTP/2:如何提升网络速度?

  • RTT: 单次请求响应
  • HTTP1.1不能将带宽跑满
  • HTTP2实现了并行请求

在这里插入图片描述

在这里插入图片描述

  • HTTP2的特性
  • 可是设置请求优先级
  • 多路复用是HTTP2最核心的功能
  • 服务器可以主动推送, 就不用等着请求再要
  • 头部压缩: 请求头和响应头
  • 影响HTTP/1.1效率的主要原因: TCP的慢启动, 多条TCP链接竞争带宽, 队头阻塞
  • HTTP/2多路复用在协议栈中添加了二进制分帧层
  • 但是还是基于TCP的, 还是会出现数据包的队头阻塞
  • TCP的慢启动: 发送数据由慢到快: 为了解决网络拥塞
  • HTTP2思路是一个域名只使用一个TCP长连接传输数据, 这样只需要一次慢启动, 同时也避免了多个TCP链接竞争资源
  • 解决队头阻塞问题采用并行请求, 就是任何时候都可以请求, 不需要等待上一个请求完成.

31|HTTP/3:甩掉TCP、TLS 的包袱,构建高效网络

  • HTTP3解决HTTP/2的TCP的队头阻塞问题
  • TCP 传输过程中,由于单个数据包的丢失而造成的阻塞称为 TCP 上的队头阻塞。
  • 这不同于 HTTP/1.1,使用 HTTP/1.1 时,浏览器为每个域名开启了 6 个 TCP 连接,如果其中的 1 个 TCP 连接发生了队头阻塞,那么其他的 5 个连接依然可以继续传输数据。
  • 所以随着丢包率的增加,HTTP/2 的传输效率也会越来越差。有测试数据表明,当系统达到了 2% 的丢包率时,HTTP/1.1 的传输效率反而比 HTTP/2 表现得更好。
  • 除了 TCP 队头阻塞之外,TCP 的握手过程也是影响传输效率的一个重要因素。
  • 网络延迟又称为 RTT(Round Trip Time)。我们把从浏览器发送一个数据包到服务器,再从服务器返回数据包到浏览器的整个往返时间称为 RTT
  • RTT 是反映网络性能的一个重要指标。
  • 我们知道 HTTP/1 和 HTTP/2 都是使用 TCP 协议来传输的,而如果使用 HTTPS 的话,还需要使用 TLS 协议进行安全传输,而使用 TLS 也需要一个握手过程,这样就需要有两个握手延迟过程。
  • 在建立 TCP 连接的时候,需要和服务器进行三次握手来确认连接成功,也就是说需要在消耗完 1.5 个 RTT 之后才能进行数据传输。
  • 进行 TLS 连接,TLS 有两个版本——TLS1.2 和 TLS1.3,每个版本建立连接所花的时间不同,大致是需要 1~2 个 RTT
  • 如果浏览器和服务器的物理距离较近,那么 1 个 RTT 的时间可能在 10 毫秒以内
  • 但如果服务器相隔较远,那么 1 个 RTT 就可能需要 100 毫秒以上了
  • HTTP/3采用了UDP协议, 基于 UDP 实现了类似于 TCP 的多路数据流、传输可靠性等功能,我们把这套功能称为QUIC 协议
  • 实现了类似 TCP 的流量控制、传输可靠性的功能
  • 集成了 TLS 加密功能
  • 实现了 HTTP/2 中的多路复用功能
  • 实现了快速握手功能
  • HTTP/3还是存在很多挑战: 因为系统对UDP的优化程度没有TCP好会丢包
  • TCP+HTTP/2 的多路复用 +TLS 等功能 QUIC协议

32 | 同源策略:为什么XMLHttpRequest不能跨域请求资源?

  • 在没有安全保障的 Web 世界中,我们是没有隐私的,因此需要安全策略来保障我们的隐私和数据的安全。
  • 比如你打开了一个银行站点,然后又一不小心打开了一个恶意站点,如果没有安全措施,恶意站点就可以做很多事情:修改银行站点的 DOM CSSOM 等信息;在银行站点内部插入 JavaScript 脚本;劫持用户登录的用户名和密码;读取银行站点的 Cookie、IndexDB 等数据;
  • 如果两个 URL 的协议、域名和端口都相同,我们就称这两个 URL 同源
  • 浏览器默认两个相同的源之间是可以相互访问资源和操作 DOM 的
  • 同源策略限制了不同源的站点读取当前站点的 Cookie、IndexDB、LocalStorage 等数据
  • 为了解决XSS工具引入CSP 的核心思想是让服务器决定浏览器能够加载哪些资源,让服务器决定浏览器是否能够执行内联 JavaScript 代码。通过这些手段就可以大大减少 XSS 攻击。
  • 两个不同源的 DOM 是不能相互操纵的,因此,浏览器中又实现了跨文档消息机制,让其可以比较安全地通信。 CORS

33 | 跨站脚本攻击(XSS):为什么Cookie中有HttpOnly属性?

  • 默认 XMLHttpRequest 和 Fetch 不能跨站请求资源,然后又通过 CORS 策略来支持其跨域。
  • XSS就是跨站脚本
  • 喜马拉雅的存储性XSS攻击用户设置专辑名称时,服务器对关键字过滤不严格,比如可以将专辑名称设置为一段 JavaScript
  • 一句话前端传来的内容都不可信
  • HttpOnly的cookie只能通过HTTP请求, 不能通过js读取

34 | CSRF攻击:陌生链接不要随便点

  • 邮箱被盗执行恶意脚本
  • CSRF攻击会利用用户的登录状态发起攻击利用好cookie的SameSite属性, 前后端分离会禁止CSRF但是通过auth2规范, 带上token
  • CSRF token post请求会带上csrftoken

35 | 安全沙箱:页面和系统之间的隔离墙

36 | HTTPS:让数据传输更安全

  • 页面安全, 系统安全, 网络安全

在这里插入图片描述

  • 非对称传输秘钥, 对称传输数据.
  • 服务器返回数字证书, 而不是直接返回公钥, 因为证书无法伪造
  • 向CA申请数字证书, 通过hash函数计算提交的明文信息, 并得出摘要, 然后用私钥对摘要加密, 密文就是CA给极客时间的数字签名
  • 要确保私钥永远自己保存
  • https://freessl.cn 免费申请https证书

结束语 | 大道至简

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值