从源码到执行:引擎的完整旅程
很多开发者知道"V8 是 Chrome 的 JavaScript 引擎",但说不清楚它具体做了什么。更重要的是,理解 V8 的执行流程,直接影响如何写出性能更好的代码——为什么同样的逻辑,换一种写法就快了几倍?为什么某些操作会让代码突然变慢?这些问题的答案,都藏在 V8 的执行…
我不知道的 V8 — 系列导读与阅读路径
很多开发者知道"V8 是 Chrome 的 JavaScript 引擎",但说不清楚它具体做了什么。更重要的是,理解 V8 的执行流程,直接影响如何写出性能更好的代码——为什么同样的逻辑,换一种写法就快了几倍?为什么某些操作会让代码突然变慢?这些问题的答案,都藏在 V8 的执行…
在 JavaScript 里,函数既是对象(typeof fn === 'function',但 fn instanceof Object === true),又是可执行的代码块。这个"双重身份"不是语言层面的比喻,而是 V8 内部有具体实现的机制。一个普通对象写了 foo()…
"字典是非线性数据结构"这句话在很多前端技术文章里出现,但很少有人解释清楚:这里的"非线性"是什么意思,和"线性"相比到底差在哪,以及 V8 为什么要在对象属性存储上区分线性和非线性。
我不知道的 React — 系列导读与阅读路径
执行 npm install react 之后,大多数人会紧跟一条 npm install react-dom,然后再也不会想起这件事。两个包装完,开始写组件,一切理所当然。
很多人以为 Fiber 只是 React 16 引入的一种新数据结构,但实际上,它是一整套调度系统——包含数据结构、遍历算法、时间分片机制和优先级模型。React 团队花了两年重写核心引擎,不是为了换个数据结构,而是为了让渲染这件事变得"可商量"。
很多人以为 JSX 就是在 JavaScript 里写 HTML,但实际上浏览器根本不认识 JSX。它既不是合法的 JavaScript,也不是真正的 HTML——它是一层语法糖,需要经过编译才能执行。
我不知道的 Pixi.js — 系列导读与阅读路径
很多人以为 Pixi.js 就是"在 canvas 上画图的库",但实际上——它是一个完整的渲染管线系统。从 v8 开始,Pixi.js 同时支持 WebGL 和 WebGPU 两套后端,渲染架构也因此经历了一次彻底重构。
很多人以为 Pixi.js 的纹理就是"把图片贴到 Sprite 上",但实际上纹理管理涉及三层抽象:TextureSource(GPU 上的图像数据)、Texture(纹理上的矩形区域)、Sprite(屏幕上的可渲染对象)。搞清楚这三层关系,大部分纹理相关的性能问题和内存泄漏…
Pixi.js 能渲染画面,但画面要能点、能拖、能悬停,才算一个完整的应用。很多人以为 Pixi.js 的事件就是"给 Sprite 绑个回调",但实际上——v8 的事件系统经历了一次彻底重构,从 InteractionManager 切换到了基于 W3C 标准的 EventS…
我不知道的 VSCode 扩展 — 系列导读与阅读路径
一、很多人用 VSCode,但不知道扩展是怎么"插"进去的
上一篇提到,VSCode 扩展的很多能力是通过 package.json 声明式注册的。菜单、视图、状态栏就是最典型的三个——它们决定了用户"看到什么"和"怎么交互"。
上一篇介绍的菜单和树视图能覆盖大部分交互场景,但它们有一个共同的限制——只能展示 VSCode 预定义的 UI 组件。如果需要一个表单、一个图表、一个富文本编辑器,TreeView 就无能为力了。
我不知道的打包工具 — 系列导读与阅读路径
Webpack、Rollup、esbuild、Vite、Rolldown——前端打包工具的名单每隔一两年就多一个。直觉上,这像是 JavaScript 社区的造轮子癖。
一个 TypeScript 库项目,用 Webpack 构建需要 30 秒,换成 tsup 只要 0.5 秒。快了 60 倍。这不是玄学,也不是"优化了配置"的结果——背后是语言级别的架构差异。
你发布了一个 npm 包,TypeScript 编译通过了,本地测试也没问题。用户 require 你的包,报错;换成 import,还是报错。问题出在哪?
我不知道的HTTP — 系列导读与阅读路径
面试中有一道经典题:"从输入 URL 到页面呈现,中间发生了什么?"
很多人以为 Cookie 就是"在浏览器里存个值",需要的时候取出来用。但实际上,Cookie 和 localStorage 有一个本质区别:Cookie 会在每一次 HTTP 请求中被自动携带发送到服务器。
很多人以为浏览器缓存就是"强缓存和协商缓存两种",面试能说出这两个词就算过关。但实际上,缓存不是一个二选一的开关——它是一条从客户端到代理再到源服务器的完整链路,每一级都有自己的缓存策略,每一级都可能返回不同的响应。
我不知道的浏览器 — 系列导读与阅读路径
很多人对浏览器有一个直觉判断:打开 Chrome,任务管理器里出现一大堆进程,"Chrome 又在吃内存了"。但这些进程分别是什么?为什么不设计成一个进程?一个标签页崩溃为什么不会把整个浏览器拖垮?
"JavaScript 是单线程的"——这句话几乎每个前端开发者都说过,但很少有人追问一句:为什么?
很多人以为 setTimeout(fn, 0) 就是"立即执行",但实际上——它排在所有当前微任务之后,排在浏览器渲染之后,有时候甚至要等几毫秒。
我不知道的 i18next — 系列导读与阅读路径
很多人把 i18next 的命名空间当成"翻译文件的分类文件夹",配置一下 ns 数组就完事了。但命名空间决定的不只是文件怎么分,它直接影响了资源的加载粒度、请求数量和内存占用。一个看似简单的配置选择,可能导致首屏多发十几个请求,也可能让翻译资源在内存里无限堆积。
在 React 项目里用 i18next,很多人一遇到翻译就条件反射般地用 Trans 组件。但实际上,大部分场景 t() 函数就够了,Trans 只在特定条件下才有存在的必要。搞不清两者的边界,轻则代码臃肿,重则引入不必要的渲染开销。
很多人以为复数就是"1 个用单数,2 个及以上用复数"——英语确实如此,但放到阿拉伯语里,复数有 6 种形式;放到波兰语里,"2-4"和"5-21"用不同的词形。i18next 的复数处理远不止加个 _plural 后缀那么简单,而且从 v21 开始,连后缀的命名方式都彻底变了。
我不知道的 dumi — 系列导读与阅读路径
我不知道的 bugs — 系列导读与阅读路径
我不知道的 CSS — 系列导读与阅读路径
我不知道的 WebSocket — 系列导读与阅读路径