如何使用shell脚本优化前端构建性能

817 阅读3分钟

这里介绍的优化策略主要适用于打包构建过程中存在部分逻辑可以并行执行的情况。

作为前端开发,一个shell常用的场景是执行编译构建流程,比如执行打包逻辑,再将构建产物上传等等。

一般我们是串行执行整个过程的,因为打包完成之后才有产物,我们再将产物上传。但是一些特殊项目,比如多入口、多端项目,我们可能需要执行两次编译打包过程,比如第一次打包出PC端产物,第二次打包出移动端产物。这个时候如果我们再以串行的方式执行整个构建过程,那么效率会很低。

那么有没有什么办法优化这个过程呢?

可以使用shell background function,让其在后台并行执行多个任务,然后通过wait等待所有后台任务都执行完毕之后,再执行后续流程。

那么如何让脚本在后台执行呢?答案就是&

基础实现

#!/bin/bash
echo "start to build"

build_pc() {
  echo 'build pc dist'
}

build_mobile() {
  echo 'build mobile dist'
  # 用来测试,2s后才会输出done,说明wait会等待两个函数都执行完才继续
  sleep 2
}

build_pc &
build_mobile &

echo '说明上面两个函数是进入后台执行了,没有阻塞这段代码执行'

wait
echo 'done'

输出:

start to build
说明上面两个函数是进入后台执行了,没有阻塞这段代码执行
build pc dist
build mobile dist
done // 2s 后输出这个

发现的问题

实际生产使用中,发现一个问题就是background function执行如果exit非0,也就是执行出错了,或者说构建失败了,并不会导致整个脚本失败,我们来看下面代码:

echo "start to build"
# exit 1

build_pc() {
  echo 'build pc dist'
  exit 1
}
build_pc &

wait
echo 'done'

输出:

start to build
build pc dist
done

但如果是这样:

echo "start to build"
exit 1

build_pc() {
  echo 'build pc dist'
  exit 1
}
build_pc &

wait
echo 'done'

只会输出:

start to build

那我们要怎么解决这个问题呢?

我们可以这样:

echo "start to build"
JOB_FAIL_COUNT=1

build_pc() {
  echo 'build pc dist'
  # exit 1
}
build_pc &
build_pc_job_id=$!

wait $build_pc_job_id && JOB_FAIL_COUNT=$((JOB_FAIL_COUNT-1))

echo $JOB_FAIL_COUNT
echo 'done'

输出:

start to build
build pc dist
0
done

如果我们background function异常退出了:

start to build
build pc dist
1
done

可以看到JOB_FAIL_COUNT会是1,这个时候我们可以exit JOB_FAIL_COUNT,保证整个任务可以异常退出,不会出现后台函数执行异常了,整个脚本最终还成功的。

最终实现:

echo "start to build"
JOB_FAIL_COUNT=2

build_pc() {
  echo 'build pc dist'
}

build_mobile() {
  echo 'build pc dist'
}

build_pc &
build_pc_job_id=$!
build_mobile &
build_m_job_id=$!

wait $build_pc_job_id && JOB_FAIL_COUNT=$((JOB_FAIL_COUNT-1))
wait $build_m_job_id && JOB_FAIL_COUNT=$((JOB_FAIL_COUNT-1))

echo $JOB_FAIL_COUNT
echo 'done'

其他用法

后台执行这个功能还可以应用在命令行中,比如我们经常需要在本地启动mongodb或者redis-server服务,通常我们直接在终端中执行:redis-server启动服务,但是这样会有一个问题就是你一旦ctrl + c,服务就关停了。

那么我们可以以这样的方式执行:redis-server &。这样你当前终端就可以继续执行其他命令了。