前端工具链介绍
- Parser - 解析成 AST,让后面的工具使用
- babel,tsc
- swc,esbuild
- Formatter - 格式化源代码
- prettier
- Linter - 检测错误
- eslint,tslint
- Transpiler -Down-level JavaScript
- babel,tsc
- esbuild,swc
- Minifier - 亚索代码
- uglify,terser
- Google Closure Compiler(Java)
- esbuild,(swc)
js工具链为什么慢
- 预研自身 - Runtimes
- Chrome,Node.js,Deno - V8
- Firefox - SpiderMonkey
- Safari,Bun - JavaScriptCore
- JIT(Just in Time)
- 边解析边编译
- 需要启动时间
- 没有最优的CPU指令优化
- 内存和GC(Garbage Collection)
- 运行时GC影响性能
前端工具链趋势
- Deno,Bun
- 用Rust/Xig 统一Runtime
- swc,esbuild
- 用Rust/Go重写Bundler
- Rome TOols
- 用Rust统一全家桶
性能应用需要处理的核心问题
Concurrency vs Parallelism | 并发 vs 并执行
- Concurrency - 并发
- 同一时间执行更多的人物
- 各种async模型
Native(Rust/Go) 工具链为什么快
- 不单单是多合
- 编译到最优CPU指令
- Rust - LLVM
- Go - 定制
- 优秀的内存管理
- Rust - 声明周期
- Go - 业界最先进的GC
- 层层优化
- 极致到每一个比特的使用
- 系统API调用
- 优秀的性能排查工具
ESLint的痛点
- ESLint性能问题渐渐成为了我们的瓶颈
- 极其复杂的配置系统
- 无法提升能力的插件系统
- 没有去分开代码风格和代码错误两种基本问题
- 没有静态类型分析,需要引入 TypeScript,这会变得特别慢
- 难处理巨型Monorepo - 十几万文件,几百万行代码
Rust自研js编译器特点
- 一体式架构,不考虑插件系统
- 多可处理每一个文件、每一条Linter规则
- 压榨LLVM,用更有的CPU指令集
- 使用Memory Arena内存池,用各种工具排查和优化内存使用情况
性能优化经验
- 性能不是白给的,需要花时间打磨
- Cache Locality - 缓存访问局部性
- 想方设法减少数据结构的内存,让它进 CPU/L1/L2缓存
- 在Hot Path上面统计使用频率,决定是否引入跟高一层的缓存(Heap, Disk)
- 申请和释放内存真的很耗时
- 改为使用内存池后,性能提升20%+
- 一些系统API会无意间使用内存,劲量统一申请,提前申请容量(Capacity)
- 系统学习排查性能问题
- 多看其他编译器源码,学习细节
- 学会统计Code Path 的执行次数,决定是否使用缓存
Rust vs Go
Rust有更多更新的体验,检测出来的问题更多,编译器能做的东西越多越好