Optimize lazy loading performance

zsh-nvm is pretty slow to load even with NVM_LAZY_LOAD=1 due to the
presence of a lots of global binaries. I have ~110 global binaries
installed, zprof shows that `_zsh_nvm_lazy_load` alone takes 113.23ms,
causing noticable delay during shell startup.

Further profiling shows that when there are a lot of global binaries,
running `basename` on each of them (because `xargs -n1`) is pretty slow,
the same goal could be achieved via zsh builtin expansion flags or
modifiers and it's much faster. Running `which` in a for loop also has a
similar but less significant drawback.

After the change zsh-nvm loads in 6.03ms under same conditions.

Additionally, added proper quoting to guard against binaries with
whitespaces in their name. This has near to zero real-world impact but
still, it is the correct thing to do.
This commit is contained in:
Riatre Foo 2021-02-09 01:14:35 +08:00
parent 23067bd9bb
commit dda8bb6165

View File

@ -22,20 +22,6 @@ _zsh_nvm_install() {
$(builtin cd "$NVM_DIR" && git checkout --quiet "$(_zsh_nvm_latest_release_tag)") $(builtin cd "$NVM_DIR" && git checkout --quiet "$(_zsh_nvm_latest_release_tag)")
} }
_zsh_nvm_global_binaries() {
# Look for global binaries
local global_binary_paths="$(echo "$NVM_DIR"/v0*/bin/*(N) "$NVM_DIR"/versions/*/*/bin/*(N))"
# If we have some, format them
if [[ -n "$global_binary_paths" ]]; then
echo "$NVM_DIR"/v0*/bin/*(N) "$NVM_DIR"/versions/*/*/bin/*(N) |
xargs -n 1 basename |
sort |
uniq
fi
}
_zsh_nvm_load() { _zsh_nvm_load() {
# Source nvm (check if `nvm use` should be ran after load) # Source nvm (check if `nvm use` should be ran after load)
@ -85,7 +71,7 @@ _zsh_nvm_lazy_load() {
if [[ "$NVM_NO_USE" == true ]]; then if [[ "$NVM_NO_USE" == true ]]; then
global_binaries=() global_binaries=()
else else
global_binaries=($(_zsh_nvm_global_binaries)) global_binaries=("$NVM_DIR"/v0*/bin/*(N:t) "$NVM_DIR"/versions/*/*/bin/*(N:t))
fi fi
# Add yarn lazy loader if it's been installed by something other than npm # Add yarn lazy loader if it's been installed by something other than npm
@ -95,19 +81,22 @@ _zsh_nvm_lazy_load() {
global_binaries+=('nvm') global_binaries+=('nvm')
global_binaries+=($NVM_LAZY_LOAD_EXTRA_COMMANDS) global_binaries+=($NVM_LAZY_LOAD_EXTRA_COMMANDS)
# Deduplicate
typeset -U global_binaries
# Remove any binaries that conflict with current aliases # Remove any binaries that conflict with current aliases
local cmds local cmds
cmds=() IFS=$'\n' cmds=($(whence -w -- "${global_binaries[@]}" 2> /dev/null))
for bin in $global_binaries; do unset IFS
[[ "$(which $bin 2> /dev/null)" = "$bin: aliased to "* ]] || cmds+=($bin) cmds=(${cmds#*": alias"})
done cmds=(${(@q-)cmds%": "*})
# Create function for each command # Create function for each command
for cmd in $cmds; do for cmd in $cmds; do
# When called, unset all lazy loaders, load nvm then run current command # When called, unset all lazy loaders, load nvm then run current command
eval "$cmd(){ eval "$cmd(){
unset -f $cmds > /dev/null 2>&1 unset -f ${cmds[@]} > /dev/null 2>&1
_zsh_nvm_load _zsh_nvm_load
$cmd \"\$@\" $cmd \"\$@\"
}" }"