Node 庫以多種方式處理異步功能。最常見的模式是 error-first callbacks,但是你還可能會遇到 streams、promises、event emitters、child processes, 或 observables。gulp 任務(task)規(guī)范化了所有這些類型的異步功能。
當從任務(task)中返回 stream、promise、event emitter、child process 或 observable 時,成功或錯誤值將通知 gulp 是否繼續(xù)執(zhí)行或結(jié)束。如果任務(task)出錯,gulp 將立即結(jié)束執(zhí)行并顯示該錯誤。
當使用 series() 組合多個任務(task)時,任何一個任務(task)的錯誤將導致整個任務組合結(jié)束,并且不會進一步執(zhí)行其他任務。當使用 parallel() 組合多個任務(task)時,一個任務的錯誤將結(jié)束整個任務組合的結(jié)束,但是其他并行的任務(task)可能會執(zhí)行完,也可能沒有執(zhí)行完。
const { src, dest } = require('gulp');
function streamTask() {
return src('*.js')
.pipe(dest('output'));
}
exports.default = streamTask;
function promiseTask() {
return Promise.resolve('the value is ignored');
}
exports.default = promiseTask;
const { EventEmitter } = require('events');
function eventEmitterTask() {
const emitter = new EventEmitter();
// Emit has to happen async otherwise gulp isn't listening yet
setTimeout(() => emitter.emit('finish'), 250);
return emitter;
}
exports.default = eventEmitterTask;
const { exec } = require('child_process');
function childProcessTask() {
return exec('date');
}
exports.default = childProcessTask;
const { Observable } = require('rxjs');
function observableTask() {
return Observable.of(1, 2, 3);
}
exports.default = observableTask;
如果任務(task)不返回任何內(nèi)容,則必須使用 callback 來指示任務已完成。在如下示例中,callback 將作為唯一一個名為 cb() 的參數(shù)傳遞給你的任務(task)。
function callbackTask(cb) {
// `cb()` should be called by some async work
cb();
}
exports.default = callbackTask;
如需通過 callback 把任務(task)中的錯誤告知 gulp,請將 Error 作為 callback 的唯一參數(shù)。
function callbackError(cb) {
// `cb()` should be called by some async work
cb(new Error('kaboom'));
}
exports.default = callbackError;
然而,你通常會將此 callback 函數(shù)傳遞給另一個 API ,而不是自己調(diào)用它。
const fs = require('fs');
function passingCallback(cb) {
fs.access('gulpfile.js', cb);
}
exports.default = passingCallback;
gulp 不再支持同步任務(Synchronous tasks)了。因為同步任務常常會導致難以調(diào)試的細微錯誤,例如忘記從任務(task)中返回 stream。
當你看到 "Did you forget to signal async completion?" 警告時,說明你并未使用前面提到的返回方式。你需要使用 callback 或返回 stream、promise、event emitter、child process、observable 來解決此問題。
如果不使用前面提供到幾種方式,你還可以將任務(task)定義為一個 async 函數(shù),它將利用 promise 對你的任務(task)進行包裝。這將允許你使用 await 處理 promise,并使用其他同步代碼。
const fs = require('fs');
async function asyncAwaitTask() {
const { version } = fs.readFileSync('package.json');
console.log(version);
await Promise.resolve('some result');
}
exports.default = asyncAwaitTask;
更多建議: