跳到主要内容

知识点简述

网络基础

UDP: 
- 特点:面向报文、尽最大努力交付、一对多、无连接、没有拥塞控制
- 面向报文传输:UDP协议的数据传输是基于报文的,每个UDP报文都作为一个独立的单元进行传输,不拆分、不合并。
- 无连接:UDP在传输数据之前不需要建立连接,也不需要在传输完成后断开连接。
- 尽最大努力交付:UDP不保证数据的可靠性,数据包可能会丢失、重复或乱序到达。协议仅尝试发送数据,不保证成功到达。
- 一对多:UDP支持单播、多播和广播,可以用于一对多的通信模式。
- 没有拥塞控制:UDP没有内置的拥塞控制机制,这意味着在网络拥塞时,UDP不会自动减少发送数据的速率。
- 使用场景:适用于需要低延迟和不要求高可靠性的,如实时音视频传输、在线游戏和DNS查询等。
TCP: 
- 特点:面向字节流、可靠、一对一、有连接、双全工通信
- 面向字节流:TCP将应用层的数据视为连续的字节流进行传输,而不是独立的报文或数据包。这意味着,发送方可以连续发送数据,而接收方可以以任意大小读取数据。
- 可靠:TCP提供可靠的数据传输,通过使用确认(ACK)、重传(Retransmission)、序列号(Sequence Number)和校验和(Checksum)等机制,确保数据包能够正确到达目标地址。如果数据在传输过程中丢失或损坏,TCP会自动重传这些数据。
- 一对一:TCP连接是点到点的,即一条TCP连接只能在两个主机之间建立和使用。这意味着,每个TCP连接都是唯一的,并且只能在两个端点之间进行通信。
- 有连接:在进行数据传输之前,TCP需要在通信双方之间建立连接。这通常通过“三次握手(Three-Way Handshake)”过程完成。一旦连接建立,数据可以在两端之间可靠地传输。
- 双全工:TCP支持双全工通信,这意味着数据可以同时在两个方向上独立传输。发送方和接收方可以同时发送和接收数据,而不会相互干扰。

- 三次握手:
- 1. 客户端发送SYN,表示希望建立连接,并发送自己的初始序列号。
- 2. 服务器收到SYN后,返回SYN-ACK,表示同意建立连接,并发送自己的初始序列号,同时确认收到了客户端的SYN。
- 3. 客户端收到SYN-ACK后,发送ACK,确认收到了服务器的SYN。
- 原因:建立可靠的连接,确保双方都有能力发送和接收数据,并初始化序列号。
- 四次挥手:
- 客户端发送FIN,表示希望关闭连接。
- 服务器收到FIN后,返回ACK,表示收到了客户端的FIN,但服务器可能还有数据未发完。
- 服务器确认所有数据发送完毕后,发送FIN,表示希望关闭连接。
- 客户端收到FIN后,返回ACK,表示收到了服务器的FIN,并进入TIME_WAIT状态。
- 原因:
- 可靠地终止连接,确保双方都同意关闭连接,并且所有数据都已传输完毕。
- 使用场景:http

HTTP 
- 优点:简单、灵活、易于扩展、应用广泛、跨平台
- 缺点:无状态、明文传输、不安全
HTTP/1.1
- 长连接: keep-alive
- 只要任意一端没有提出断开连接,则保持tcp的连接
- 管道网络传输
- 可以发送多个请求,但是响应需要按照接收请求的顺序返回
- 队头阻塞
- 当一个请求被阻塞时,后面的请求需要等待
HTTP/2
- 头部压缩
- 同时发送多个请求,头部相同
- 服务端推送
- 服务端可以主动推送消息
- 多路复用
- 采用stream复用在一条TCP,并行交错发送请求和响应。(tcp接收发生丢失,则阻塞后续处理数据)
- 二进制格式
HTTP/3
- 基于 UDP 的 QUIC 协议
- 解决对头阻塞
- stream丢失后,只会阻塞这个流,其他流不会收到影响
HTTPS
- SSL/TSL (http -> TCP中间多了一个层)
- 采用对称加密和非对称加密混合方式
- 采用非对称加密和身份证书生成用于后续通话加密的对称加密的秘钥,
跨域
- JSONP
- 利用加载静态资源实现。
- CORS
- 设置跨域头:Origin、Method、Headers
- 复杂请求发送options预检、确认上述三个跨域头
- Nginx 反向代理
- Websocket
缓存
- 强制缓存 Cache-Control
- no-cache 使用协商缓存
- no-store 不进行缓存处理
- private 客户端可以缓存
- public 客户端和代理服务器都可以缓存
- max-age=60 缓存内容将在 60 秒后失效
- 协商缓存 ETag/Last-Modified
- Last-Modified/If-Modified-Since 对比文件更新时间来缓存
- Etag/If-None-Match 针对资源文件生成唯一标识符
DNS
- 域名系统。进行域名到IP地址的转换
- 递归:本地到本地域名解析服务器
- 迭代:本地域名服务器-根域名解析服务器

浏览器

浏览器
- 进程
- 浏览器进程:负责页面展示&交互
- 渲染进程:渲染网页
- 网络进程:处理网络资源
- GPU进程:硬件加速
- 插件进程:硬件加速,提高体验

- 线程
- 主(JS引擎)线程:处理js代码(解析、执行)。消息队列不为空,循环取任务执行。由于主线程和GUI线程互斥、所以当JS任务执行过长时,会阻塞页面的渲染,造成卡顿。
- GUI渲染线程:负责解析HTML、CSS合成CSSOM树、布局树、绘制、分层、栅格化、合成。(重绘、重排、合成)和主线程是冲突的,当它执行时,主线程会被挂起;当主线程执行时,有需要此线程执行任务,保存到一个队列中,等待主线程执行完在执行。
- 事件触发线程:在js代码在解析时,遇到事件时,比如鼠标监听,会将任务添加到事件触发线程中。等事件触发时,会将任务从事件触发线程中取出,放到消息队列的队尾等待执行。
- 定时器触发线程:用于存放setTimeout/setInterval任务,在解析遇到这些任务时,主线程将这些任务放到定时器触发线程中,并开始计数,时间了之后,将任务放到消息队列中等待执行。
- HTTP请求线程:用于检测XMLHttpRequest请求,当请求状态改变时,将设置的回调函数添加到消息队列中等待执行。

- 输入URL到页面展示的过程
导航阶段
- 1. 用户:输入内容
- 1. 浏览器进程接收到地址栏的URL请求,便将该URL转发给网络进程
- 2. 网络进程:提交URL请求
- 如果是HTTP协议,此时会发起一个HTTP请求,
- 构建请求、查找本地资源缓存、查找本地DNS缓存、DNS获取IP
- 等待TCP队列、建立TCP连接、发送HTTP请求
- 网络进程发起真正的URL请求
- 服务器收到URL请求,返回响应头
- 网络进程收到响应头数据,解析响应头数据,然后转发给浏览器进程
- 3. 浏览器进程:准备渲染进程
- 浏览器进程收到数据,发送提交导航消息到渲染进程
- 渲染进程收到消息后,直接和网络进程建立数据管道,并准备接收HTML数据
- 4. 渲染进程:提交文档
- 渲染进程向浏览器进程确认提交,告诉浏览器进程:已经准备好接收和解析页面数据
- 浏览器进程收到确认提交后,便移除之前旧的文档,然后更新浏览器进程中的页面状态
--------------------
渲染阶段(浏览器进程:等待渲染进程提交新页面、渲染进程:开始渲染网页、网络进程:在渲染进程执行网页渲染时,同步下载HTML/CSS/JavaScript和图片等资源)
- 1. DOM:渲染进程将HTML内容转换为能够读懂的DOM树结构
- 2. CSSOM:渲染引擎将CSS样式表转化为浏览器可以理解的styleSheets,并计算出DOM节点的样式。
- 3. Layout:渲染引擎创建布局树,并计算元素的布局信息。
- 4. Layer:渲染引擎对布局树进行分层,并生成分层树
- 5. Paint:渲染引擎为每个图层生成绘制列表,并将其提交到合成线程
- 6. 合成线程:进行栅格化操作
- tiles:先将图层分成图块
- raster:然后在光栅化线程池中将图块转换成位图
- draw quad:最后发送绘制图块命令DrawQuad给浏览器进程
- 7. display:浏览器进程根据DrawQuad消息生成页面,并显示到显示器上

- DOM如何生成的
- 浏览器中的HTML解析器可以把HTML字符串转换成DOM结构
- HTML解析器边接收网络数据边解析HTML
- 解析DOM
- HTML字符串转Token
- Token栈用来维护节点之间的父子关系,Token会一次压入栈中
- 如果是开始标签,把Token压入栈中并创建新的DOM节点并添加到父节点的children中
- 如果是文本Token,则把文本节点添加到栈顶元素的children中,文本Token不需要入栈
- 如果是结束标签,此开始标签出栈

- 资源加载
- CSS加载不会影响DOM解析
- CSS加载不会阻塞JavaScript加载,但是会阻塞JavaScript执行
- JavaScript依赖CSS加载,JavaScript会阻塞DOM解析
- defer:顺序执行,异步下载该脚本,等待HTML解析完毕后执行脚本
- async:乱序执行,异步下载该脚本,无论当前HTML是否解析完毕都会执行脚本

- 性能指标
- FP(First Paint 首次渲染) 表示浏览器从开始请求网站到屏幕渲染第一个像素点的时间
- FCP(First Contentful Paint首次内容渲染) 表示浏览器渲染出第一个内容的时间,这个内容可以是文本、图片或SVG元素等,不包括iframe和白色背景的canvas元素
- SI(Speed Index 速度指数) 表示网页内容的可见填充速度。衡量页面加载期间内容的视觉显示速度
- LCP(Largest Contentful Paint 最大内容绘制)标记了渲染出最大文本或图片的时间。测量感知加载速度的一个以用户为中心的重要指标
- TTI(Time to Interactive可交互时间) 指标测量页面从开始加载到主要子资源完成渲染,并能够快速、可靠地响应用户输入所需的时间
- TBI(Total Blocking Time总阻塞时间) 指标测量FCP与TTI之间的总时间,这期间,主线程呗阻塞的时间过长,无法做出输入响应
- FID(First Input Delay首次输入延迟) 测量加载响应度的一个以用户为中心的重要指标
- CLS(Cumulative Layout Shift 累计布局偏移)
- 优化
- FP&FCP
- 加快服务器相应速度
- 升级服务器配置
- 合理设置缓存
- 优化数据库索引
- 加大服务器带宽
- 服务器开启gzip压缩
- 开启服务器缓存
- 避免重定向操作
- 使用dns-prefetch进行DNS预解析
- 采用域名分片技术突破6个TCP连接限制或者采用HTTP/2
- 使用CDN减少网络跳转
- 压缩JS/CSS/图片等资源
- 减少HTTP请求,合并JS/CSS,合理内嵌JS和CSS
- SI
- 最小化主线程工作
- 减少JavaScript执行时间
- 确保文本在webfont加载期间保持可见
- 避免强制同步布局和布局抖动
- LCP
- 即时加载
- 优化关键渲染路径
- TTI
- 缩小JavaScript
- 预加载关键请求

JavaScript

- 运行环境
- V8
- 解释和编译两种方式
- 解析流程 源代码 => Parse => AST => Ignition => byteCode
- Parse 将JavaScript模块转成AST(抽象语法树)
- Ignition 解释器,将AST转成ByteCode (字节码是介于AST和机器码的中间代码)
- TurboFan 编译器,将字节码编译为CPU可以直接执行的机器码


工程化

webpack
- 流程
- 1. 根据配置项参数,初始化compiler对象,调用插件的apply方法。
- 2. 根据入口文件,使用loader对其编译,并找到该文件依赖文件。递归循环这一步骤
- 3. 经过编译后,得到编译后的内容及其依赖关系,组装成一个个包含多个模块的chunk。把每个chunk转成一个单独的文件加入输出列表
- 4. 确定输出内容,根据配置项信息,进行文件写入操作
- loader
- 作用:解析非js文件类型
- 执行顺序: 根据配置信息倒序执行
- loader-running: 执行loader链条的模块。存在pitch方法则不执行后续loader
- 叠加顺序:post(后置)+inline(内联)+normal(正常)+pre(前置)
- 特殊配置: -!(不要前置和普通loader)、!(不要普通loader)、!!(只要内联loader)
- 常用loader: style-loader css-loader less-loader babel-loader
- plugin
- 作用:webpack在运行的生命周期中会广播许多事件,plugin可以监听事件,
- 实现:插件是一个类,类有一个apply方法,参数是compiler对象
- 事件流机制:将各个插件串联起来,实现的核心是tapable,基于观察者模式。
- compiler:webpack的环境配置。包含所有的配置信息,如options/loader/plugin等信息
- compilation:当监听文件变化时,会创建出一个compilation对象,包含当前模块的资源、编译输出资源、变化的文件,已经跟踪依赖的状态信息
- 常用plugin:html-webpack-plugin/ define-plugin / terser-webpack-plugin / optimize-css-assets-webpack-plugin
- source-map
- 作用:解决生产环境出现问题可以找到对应原始代码
- 配置:
- hidden-source-map: 借助第三方错误监控平台Sentry的使用
- nosources-source-map: 只会显示具体行数以及查看源代码的错误栈。安全性比 sourcemap 高
- sourcemap: 通过 nginx 设置将 .map 文件只对白名单开放(公司内网)
- 热更新原理
- 1. 创建webpack实例
- 2. 启动webpack-dev-server服务器
- 3. 添加webpack-dev-middleware中间件
- 4. 使用socketjs在浏览器端和服务器端建立一个websocket长连接
- 将webpack编译打包个各个阶段的状态信息告知浏览器端,浏览器端根据这些socket消息进行不同的操作
- 当然服务器端传递的最主要信息还是新模块的hash值,后面的步骤根据这一hash值来进行模块热替换
- 添加webpack的done事件回调,在编译完成后回向浏览器发送消息
- 5. 发送hash值
- 6. 客户端监听hash消息
- 7. 客户端说道ok的消息
- 8. 执行hotCheck方法进行更新
- 9. 向server端发送ajax请求,服务端返回一个hot-update.json文件,该文件包含了所有要更新的模块的hash值和chunk名
- 10. 通过jsonp请求获取到最新的模块代码
- 构建优化
- 缩小查找文件范围 resolve.extensions、resolve.alias、resolve.modules、module.noParse、IgnorePlugin
- 缓存配置 babel-loader、cache-loader
- 多进程处理 thread-loader、terser-webpack-plugin
- 性能优化
- 代码压缩 terser-webpack-plugin、optimize-css-assets-webpack-plugin
- 代码分割 入口文件分割、动态导入
- tree-shaking
- 静态资源上CDN