最近在嘗試配置自己的Gulp流程,方便日後有需要的時候可以直接拿出來使用。但卻發現寫好的 gulp.task竟然沒有按照希望的順序執行,後來發現是因為我忽略了 Node.js有非同步執行的特性。也就是說假設我今天按順序寫好了task1和task2,但真正執行程式的時候 task1執行過久,task2並不會等它結束才開始自己的工作,而會逕自執行。這樣會造成有相依性的任務出錯,也就是我一定要 task1先跑完才能跑 task2。
同步(sync)與非同步(async)
我搞混了這兩個概念好一陣子...因為同步字面上會讓你以為是同步進行的意思,然後事實卻不是這樣。同步與他的字面意義正好相反,反而是代表一步一步來,按照順序進行的意思。反之,非同步就是不強制按照順序執行。
我在這裡只是簡單講一下概念而已,想知道更多請看: 同步與非同步的差異 怎樣理解阻塞非阻塞與同步異步的區別?
gulp.task 執行順序
重新講一下我遇到的問題:我要按順序執行兩個任務,分別是 task1和 task2。但是因為 task1的執行速度過慢,所以在非同步執行的狀況之下會出現錯誤。
原本的程式碼示意
gulp.task('task1', function() {
gulp.src('./source/*.js')
.pipe(do _sth())
.pipe(gulp.dest('./build'));
});
gulp.task('task2', ['task1'], function() {
gulp.src('build')
.pipe(do_sth_differently())
.pipe(gulp.dest('./dist'));
});
gulp.task('default',['task2']);大意是:task1處理過後的 js檔要放到 build之下,然後 task2再將這些 js檔經過二次處裡後放到 dist下。
問題根源:非同步執行
在上面程式碼中,task2執行前會先執行 task1,但是在非同步執行的狀況之下,不等 task1完成,task2就會逕自開始運作,導致錯誤發生。所以我們的問題點就在於要如何讓 task1結束時才通知 task2開始動作。
如何讓 Gulp同步執行
官方文件中提到的幾種作法:
- return
- callback
- promise
在本篇中,我用的是最間單易懂好操作的第一種方法。
修改後的程式碼示意
// with return
gulp.task('task1', function() {
// ↓↓↓↓↓↓↓ add this return
return gulp.src('source/*.js')
.pipe(do_sth())
.pipe(gulp.dest('build'));
});
gulp.task('task2', ['task1'], function() {
// ↓↓↓↓↓↓↓ add this return
return gulp.src('build/*.js')
.pipe(do_sth_differently())
.pipe(gulp.dest('dist'));
});結果
如此一來,gulp 便會按照順序,先執行完 task1後,再執行 task2。
參考與學習資料
Gulp.js task, return on src? Running tasks in series, i.e. Task Dependency