DAILY DOCDAILY DOC
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
  • BFC 块级格式化上下文
  • Note
  • WebAssembly
  • public api
  • 位运算
  • bitwise operator
  • css实现隐藏效果
  • css snippets
  • 抖音点赞
  • js 相等判断
  • fetch ReadableStream
  • git
  • Github Actions 工作流
  • google search
  • RPC vs HTTP
  • gravatar
  • hhkb
  • Init project
  • input 文件上传
  • mac

    • Mac 使用技巧
    • alfred
    • mac shortcuts
    • shortcuts text edit
    • mac 修改host
  • 微前端
  • mock
  • nginx dump
  • nginx
  • NirCmd
  • npm
  • Operator Precedence
  • package.json
  • url query 解析
  • pnpm
  • JavaScript Precise countdown
  • react 模版
  • regexp
  • setup web development
  • telegram

    • telegram bot
  • timeFunction ease
  • 视频裁剪
  • vscode

    • vscode 高级指南
    • bracketPairs
    • jsconfig.json
    • vscode pipe into code
    • social project
    • vscode tasks
  • draggable resizable
  • windows 激活
  • 前端截图实现
  • 文本配音 富文本实现
  • 图片处理
  • 前端坐标
  • 定时任务
  • work efficient
  • 微信小程序动画实现方案
  • 排列组合
  • 数列
  • 语音驱动文字
  • 浏览器
  • 状态管理
  • 移动盒子
  • 移动端开发常用snippets
  • 设计模式
  • web performance

浏览器

从输入 URL 到页面加载的全过程

浏览器主进程 响应了用户输入的地址后。解析当前地址,并找出URL 中的域名。然后通过 IPC进程间通讯发送给网络进程。 网络进程(委托操作系统去完成): DNS解析:网络进程会根据输入的域名,将其解析为一个IP地址。 建立 TCP 连接。浏览器根据 IP 地址和端口号与服务器建立 TCP 连接。建立 TCP 连接的过程可以分为三次握手,即客户端向服务器发送 SYN 报文,服务器收到后回复 SYN-ACK 报文,客户端再回复 ACK 报文,完成连接。 发送 HTTP 请求。建立 TCP 连接后,浏览器向服务器发送 HTTP 请求。HTTP 请求的格式包括请求行、请求头和请求体。请求行包括请求方法、请求 URL 和 HTTP 版本;请求头包括请求头字段和请求头值,用于描述请求的附加信息;请求体包括请求体字段和请求体值,用于向服务器传递数据。 服务器收到浏览器发送的 HTTP 请求后,会进行相应的处理并返回 HTTP 响应。HTTP 响应的格式包括状态行、响应头和响应体。状态行包括 HTTP 版本、状态码和状态消息;响应头包括响应头字段和响应头值,用于描述响应的附加信息;响应体包括响应体字段和响应体值,用于向浏览器传递数据。 关闭 TCP 连接,tcp 4次挥手后断开连接。 渲染进程 渲染页面:一旦网络进程接收到响应,它将把响应发送到浏览器的渲染进程,渲染进程将开始解析HTML、CSS和JavaScript。最后将绘制好的位图发送给GPU 进程进行合成与渲染,输出到显示器上。

DNS解析(udp 协议)

本地缓存查询:操作系统首先会查询本地 DNS 缓存,看看是否存在对应的 DNS 记录。如果有,则直接返回对应 IP 地址。 递归查询:如果本地缓存中不存在对应的 DNS 记录,操作系统会将域名发送给本地 DNS 服务器,如果本地 DNS 服务器也没有缓存这个域名对应的 IP 地址,则本地 DNS 服务器会向根域名服务器发起请求,根域名服务器返回负责该顶级域名的权威 DNS 服务器的 IP 地址。 迭代查询:本地 DNS 服务器再向权威 DNS 服务器发送请求,权威 DNS 服务器返回下一级域名服务器的 IP 地址,本地 DNS 服务器再向下一级域名服务器发送请求,直到获取到对应的 IP 地址为止。 DNS 记录缓存:当本地 DNS 服务器获取到域名对应的 IP 地址后,会将该记录存储到本地 DNS 缓存中,以便下次查询时能够直接返回 IP 地址,从而提高查询速度。 返回 IP 地址:当本地 DNS 服务器获取到域名对应的 IP 地址后,将该 IP 地址返回给操作系统,操作系统再将 IP 地址返回给浏览器的网络进程。

TCP 3次握手

TCP的三次握手是指建立TCP连接时,客户端和服务器之间的三个步骤,具体过程如下:

客户端向服务器发送连接请求报文段(SYN):客户端首先向服务器发送一个包含 SYN(同步序列号)的连接请求报文段,请求建立连接,该报文段中还包含随机产生的一个序列号(Seq=J)。 服务器向客户端回送确认报文段(SYN + ACK):当服务器收到客户端的连接请求报文段之后,如果同意建立连接,则会向客户端发送一个响应报文段,该报文段中不仅包含了确认序号 Ack(Ack=J+1),也包含了自己随机产生的序列号 Seq=K。 客户端再次向服务器发送确认报文段(ACK):当客户端收到服务器的确认报文段之后,还需要向服务器发送一个确认报文段,该报文段中的 Ack 值为服务器发送的 Seq+1(Ack=K+1),表示已经收到服务器的响应,并确认建立连接。

经过以上三次握手,TCP连接建立成功,客户端和服务器就可以开始进行数据传输了。

TCP 4次挥手

第一次挥手(FIN_WAIT_1):主动关闭方(即客户端)发送一个FIN(Finish)信号给被动关闭方(即服务器端),表示客户端没有数据要发送了,但是可以接收数据。 第二次挥手(CLOSE_WAIT):被动关闭方接收到FIN信号后,发送一个ACK(Acknowledgement)信号,确认客户端的FIN信号,同时自己也需要主动关闭,发送FIN信号给客户端,表示被动关闭方也没有数据要发送了。 第三次挥手(LAST_ACK):客户端接收到服务器的FIN信号后,发送一个ACK信号给服务器,确认服务器的FIN信号。 第四次挥手(TIME_WAIT):被动关闭方接收到客户端的ACK信号后,等待2MSL的时间,保证客户端收到了服务器的FIN信号的确认信号,然后才真正关闭连接。这个等待时间是为了保证网络中已经收到所有报文段,若超时则会进行重传。

在这四次挥手过程中,服务器需要先发送FIN信号来关闭连接,客户端会最后发送ACK信号进行确认。这个过程是为了确保双方都能够关闭连接,防止数据的丢失和网络拥堵的发生。

渲染进程如何渲染的

解析 HTML:渲染进程首先会将 HTML 解析成 DOM 树,并确定 DOM 树的结构。 解析 CSS:渲染进程会解析 CSS 并将其转化为样式规则,与 DOM 树结合来计算样式。 构建渲染树:渲染进程会将 DOM 树和样式计算出来的结果组合成渲染树,渲染树中包含了每个元素的计算样式以及其他信息。 布局:渲染进程会为每个渲染树节点计算其在屏幕上的大小和位置。 绘制:渲染进程会将渲染树中每个节点绘制出来,转换为图像,并使用 GPU 将它们显示在屏幕上。

如何理js是单线程的

这里的单线程指的是浏览器 渲染进程中的主线程

JavaScript 作为一门单线程语言,主要有以下几个特点: 事件循环(Event Loop):JavaScript 在运行时会创建一个主线程来执行代码,同时会创建一个事件循环用于处理异步任务。事件循环会不断地从任务队列中取出任务,执行完当前的任务后,再去执行下一个任务,直到所有任务都被执行完毕。 阻塞式执行:在 JavaScript 中,如果某个任务需要很长时间才能完成,比如进行网络请求或大量计算,那么这个任务会阻塞后续代码的执行。因为 JavaScript 是单线程的,所以在这个任务执行完之前,后续代码都不能被执行。 异步编程:JavaScript 通过回调函数、Promise、async/await 等方式来处理异步编程。这些方法可以让 JavaScript 在等待异步操作完成时不阻塞后续代码的执行,从而提高程序的性能和响应速度。

浏览器多进程模型

浏览器进程(Browser Process):浏览器的主进程,负责协调各个子进程,包括维护地址栏、处理用户输入、管理各个标签页等等。 渲染进程(Renderer Process):负责显示页面内容,每个标签页都有一个独立的渲染进程。渲染进程引擎解析 HTML/CSS,并执行 JavaScript 脚本。 GPU 进程(GPU Process):用于执行 GPU 相关的任务,例如 3D 绘图和视频解码。 插件进程(Plugin Process):用于运行插件,例如 Flash 播放器。 服务进程:网络请求,文件服务等。

渲染进程主要包括一下线程

主线程(Main Thread,GUI 线程):负责处理页面的网络请求、JavaScript脚本执行、样式计算、布局计算、绘制等任务。 事件线程(Event Thread):负责处理事件,例如鼠标点击、滚动、输入等用户交互操作,通过事件循环机制与主线程通信。 定时器线程(Timer Thread):负责处理定时器,例如setTimeout、setInterval等,通过事件循环机制与主线程通信。 异步HTTP请求线程(Async HTTP Request Thread):负责处理XMLHttpRequest异步请求,通过事件循环机制与主线程通信。 Web Worker线程(Web Worker Thread):负责处理JavaScript的多线程编程,通过消息机制与主线程通信,但无法直接访问DOM。

进程间通讯

浏览器中各个进程间主要通过进程间通信(Inter-Process Communication,IPC)机制进行通讯。不同的进程之间无法直接访问对方的内存,因此需要一些特殊的方式来实现进程间通信。

常见的进程间通信方式包括: 基于操作系统的进程间通信方式,例如管道、套接字、共享内存、信号量等,这些方式一般是由操作系统提供的底层机制,可以跨平台使用。 基于进程之间共享的文件进行通信,这种方式主要用于数据量较大的场景,通常需要考虑并发读写的问题。 使用浏览器提供的专用接口进行通信,例如跨文档通信(Cross-Document Messaging 比如 window.postMessage())、Web Worker 线程间通信、BroadcastChannel、SharedWorker、Service Worker 等。

Background Tasks API

requestIdleCallback 用于在浏览器空闲时执行回调。

cancelIdleCallback 用于取消任务。

对非高优先级的任务使用空闲回调。 避免在空闲回调中改变 DOM。空闲回调执行的时候,当前帧已经结束绘制了,所有布局的更新和计算也已经完成。如果你做的改变影响了布局,你可能会强制停止浏览器并重新计算。 避免执行Promise的 resolve 和 reject ,时间不可控的任务。 在你需要的时候要用 timeout。 参考: https://developer.mozilla.org/zh-CN/docs/Web/API/Background_Tasks_API

requestAnimationFrame

该回调函数会在浏览器下一次重绘之前执行

js中垃圾回收

JavaScript 中的垃圾回收机制主要有两个策略:标记清除和引用计数。

标记清除

标记清除(Mark and Sweep)是 JavaScript 引擎最常用的垃圾回收算法。它的基本思路是通过标记那些在当前环境中可达的对象,然后清除那些未标记的对象。

标记清除算法的实现分为以下三个步骤: 标记:从根集合开始遍历,标记所有可达对象(包括全局变量、局部变量、当前调用栈、闭包等)。 清除:扫描整个堆内存,把未标记的对象进行回收。 压缩:在清除垃圾之后,移动所有存活对象,使得它们在堆中连续存放,以便提高内存分配的效率。

引用计数

引用计数是另一种常见的垃圾回收算法。它的基本思路是跟踪每个对象被引用的次数,当对象的引用计数为 0 时,就将其回收。

引用计数算法的实现需要进行如下步骤: 初始化时,将所有对象的引用计数器设置为 0。 当对象被引用时,它的引用计数器加 1。 当对象被释放时,它的引用计数器减 1。 当对象的引用计数器为 0 时,表示该对象已经不再被引用,可以进行垃圾回收。 引用计数算法的一个主要问题是循环引用的处理。当两个或多个对象相互引用时,它们的引用计数器都不会变为 0,即使它们已经不再被使用。因此,现代浏览器都采用了标记清除算法作为主要的垃圾回收算法。

V8中垃圾回收实现

在 V8 中,JavaScript 对象被分配在堆(Heap)中,堆是一个动态分配的内存池,它由 V8 垃圾回收器来管理。在堆中,每个对象都有一个 header 和一个 body,header 用于存储对象的元数据信息,如对象类型、对象大小、垃圾回收器信息等,body 则用于存储对象的数据。

V8 的堆内存管理机制采用了分代式垃圾回收机制,将堆分为新生代和老生代两个区域,每个区域使用不同的垃圾回收算法。

新生代是一个较小的区域,用于存放存活时间较短的对象,包括两个区域:From 空间和 To 空间。当一个新对象被分配时,会被放入 From 空间,当 From 空间的对象数量达到一定阈值时,会触发垃圾回收器将存活的对象复制到 To 空间,同时清空 From 空间。如果一个对象在垃圾回收后仍然存活,那么它就会被晋升到老生代。新生代使用的垃圾回收算法是 Scavenge 算法,它通过牺牲空间换取时间,来实现高速垃圾回收。

老生代是一个较大的区域,用于存放存活时间较长的对象。因为老生代中的对象数量很大,所以不能使用 Scavenge 算法,而是使用了 Mark-Sweep 和 Mark-Compact 两种算法来进行垃圾回收。当一个对象在老生代中存活时间越长,它的垃圾回收成本就越高,因为垃圾回收器需要扫描更多的对象,所以 V8 会采用一些优化技术,如增量标记、增量式垃圾回收等来减少垃圾回收器的压力,从而提高垃圾回收的效率。

除了使用分代式垃圾回收机制,V8 还采用了一些优化技术来提高内存的分配和回收效率,如对象池、对象复用等。对象池用于缓存一些常用的对象,当需要创建新对象时,先从对象池中获取对象,如果对象池中没有可用的对象,则才进行内存分配;对象复用则用于重复使用已经分配过的对象,避免频繁的内存分配和垃圾回收。 总的来说,V8 的内存分配和回收机制是一个复杂的系统,它通过分代式垃圾回收、增量式垃圾。

浏览器强缓存,协商缓存

浏览器缓存是浏览器提高网站访问速度的一种方式,其基本原理是将网站的一些静态资源(如图片、样式文件、脚本文件等)缓存在本地,下次再次访问时,如果该资源没有过期或者没有被修改,则直接使用本地缓存,而不必再次从服务器获取,这样就能够提高网站的加载速度和用户体验。浏览器缓存分为两种:强缓存和协商缓存。

强缓存

强缓存指的是在资源过期时间之前,浏览器直接从本地缓存读取资源,不再向服务器发送请求。强缓存优先级比协商缓存高,如果强缓存命中,则不会进行协商缓存的判断。 常用的缓存控制指令:

  1. Expires:用于设置资源的过期时间,值为一个绝对时间字符串,如Expires: Fri, 12 Feb 2022 08:00:00 GMT。该指令已经过时,因为它是基于服务器时间的,如果客户端与服务器时间不同步,就会导致缓存失效。
  2. Cache-Control:用于设置资源的缓存策略,该指令优先级比Expires高。常见的取值有:
  3. no-store:禁用缓存。
  4. no-cache:先向服务器发送请求,确认资源是否过期。如果过期,则获取新的资源;如果没有过期,则使用本地缓存
  5. max-age:设置资源的最大缓存时间,单位为秒,如Cache-Control: max-age=3600,表示缓存1小时。 public:表示资源可以被所有用户缓存。 private:表示资源只能被单个用户缓存,通常用于个人用户的私有数据。

协商缓存

协商缓存指的是在资源过期时间之后,浏览器向服务器发送请求,服务器根据资源是否修改来决定是否返回新的资源,如果资源没有修改,则返回304状态码,浏览器从本地缓存读取资源;如果资源有修改,则返回新的资源,状态码为200或其他合适的状态码。 常用的缓存控制指令: Last-Modified/If-Modified-Since:用于记录资源的最后修改时间,浏览器在请求资源时,会将该时间通过If-Modified-Since请求头发送给服务器。如果资源的最后修改时间早于If-Modified-Since的时间,则返回304状态码,否则返回200状态码,并携带最新的资源。 ETag/If-None-Match:用于记录资源的唯一标识符,浏览器在请求资源时,会将该标识符通过If-None-Match请求头发送给服务器。如果资源的ETag值与If-None-Match的值相同,则

dom 操作为什么耗时

JavaScript 代码运行在渲染进程的主线程上,而 DOM 操作需要在渲染线程中进行,这就需要在主线程和渲染线程之间通过IPC进行通信,这个过程也需要耗费一定的时间。 操作 DOM 元素可能会导致页面重排和重绘,这个过程也需要耗费一定的时间。

优化策略: 尽量减少 DOM 操作的次数,合并多个 DOM 操作为一个。 尽量使用 documentFragment 对象进行 DOM 操作。 尽量使用 classList 对象代替 className 进行样式操作。 使用 CSS3 中的 transform 和 opacity 等属性进行动画效果。 尽量将 DOM 脱离文档流,避免重排和重绘。

解决跨域

JSONP

JSONP(JSON with Padding)是一种跨域数据传输的技术,其原理是通过在客户端动态创建 <script> 标签,通过 script 的 src 属性请求服务器上的 JSON 数据,由于 script 标签的 src 属性不受同源策略的限制,因此可以跨域请求数据。 script src加载的是 javascript 脚本,需要修改返回值类型。 const script = document.createElement('script'); script.src = http://www.test.com?callback=getData; document.body.appendChild(script);

function getData(data) { // } 返回值类型 'Content-Type': 'text/javascript' 并且返回值需要包裹成一个函数字符串${callback}(${json})。客户端服务器都要修改,比较麻烦。

Javascript
const http = require('http');
const url = require('url');

http
  .createServer((req, res) => {
    const params = url.parse(req.url, true).query;
    const callback = params.callback;

    const data = { message: 'Hello, World!' };
    const json = JSON.stringify(data);

    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.end(`${callback}(${json})`);
  })
  .listen(3000, () => {
    console.log('Server is listening on port 3000');
  });

CORS

添加 Access-Control-Allow-Origin、Access-Control-Allow-Methods 等响应头来允许跨域请求。

web worker

Javascript

var worker = new Worker('worker.js');
worker.postMessage({data: 'Hello World'});
worker.js 

self.addEventListener('message', function(event) {
    var data = event.data;
    var result = doSomeCalculation(data);
    self.postMessage(result);
});
Last Updated:
Contributors: rosendo
Prev
语音驱动文字
Next
状态管理