缘起
最近突然发现 ZSH 的启动速度很慢,受不了了,于是又折腾了一番,进行了一下排查和优化
排查
zsh 启动时间
查看 omz 启动过程花费的时间
for i in {1..10}; do time zsh -i -c exit; sleep 0.1; done;
平均花费时间在 0.5s 左右,确实很慢查看详细的加载项花费的时间
跟 C、Python 等语言类似,zsh 提供了专门的 profiling 模块zprof
用于衡量每个 zsh 函数的执行耗时比例,在~/.zshrc
文件第一行添加下列命令加载zprof
zmodload zsh/zprof
然后
source ~/.zshrc
重新加载 zsh 模块
使用zprof
命令获取各个函数加载时间
可以看到前几个都是nvm
,测试一下,注释掉~/.zshrc
中nvm
部分# NVM 配置 # export NVM_DIR="$HOME/.nvm" # [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm # [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
再测试一下加载时间
加载速度显著提高
优化方案
1. NVM 手动懒加载
把原有的 NVM 配置替换成函数,需要使用时再进行调用
# NVM 懒加载
nvm() {
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
nvm "$@"
}
缺点是每次使用 npm
前都需要先调用 nvm
进行加载
2. zsh-nvm 插件懒加载
插件安装
git clone https://github.com/lukechilds/zsh-nvm ~/.oh-my-zsh/custom/plugins/zsh-nvm
修改 ~/.zshrc
配置,删除原有的 NVM
的启动部分,开启 zsh-nvm
的懒加载
# 启用插件
plugins=(
...
zsh-nvm
)
# 开启懒加载
export NVM_LAZY_LOAD=true
效果
确实有显著提升,但是实际体验中每次新建终端还是有明显延迟感
3. fnm 替代 nvm (最终方案,墙裂推荐)
先放效果图
加载时间
这回在 zprof
根本看不到 fnm
的影子
fnm 的使用
安装 fnm
fnm 的安装比较简单,一行脚本足矣
curl -fsSL https://fnm.vercel.app/install | bash
安装完毕后会自动配置到 ~/.zshrc
中,如果没有的手动添加以下配置重新加载就可以了
# fnm
export PATH=$HOME/.fnm:$PATH
eval "`fnm env`"
使用 fnm
fnm
使用方式和 nvm
大同小异
fnm list-remote # 列出所有 node 版本
fnm install v18.4.0 # 安装对应版本,版本号从 list-remote 获取
fnm default v18.4.0 # 设置全局默认 node 版本
fnm use v16.15.1 # 设置当前终端版本,重启终端后失效
fnm current # 查看当前使用 node 版本
收尾:卸载 nvm
删除 NVM
文件夹,然后删除 ~/.zshrc
中相关配置即可
rm -rf ~/.nvm # 删除 NVM 文件夹
关于 fnm 和 nvm
其实关于两者的速度差这么多,个人猜测大概的原因就是使用的语言问题了nvm
用的是 shell
,而 fnm
则是使用 Rust
编写的
现在提起 Rust
估计大家第一时间的想到的就是快
为了这点终端启动体验,又花了不少时间,真是充实而又白给的一天
不过这不就是程序员应有的追求吗(笑)
一点小坑
在看 zprof 信息 的时候还注意到了 compdump
和 compinit
耗费的启动时间也不少
不过今天就到这了,毕竟程序员的哲学之一不是够用就好,过度优化是万恶之源吗(再笑)
留下一个坑,有空再研究