Gulp串行任务未等待内部复制函数完成的问题咨询
Gulp Series 任务未等待异步文件复制完成就执行构建的解决方案
我完全懂你遇到的问题——Gulp 的 series 本来该串行执行任务,但 copy_sass 里的文件复制还没做完,css_build 就已经启动了,导致构建找不到文件。这是因为你在 copy_sass 里错误地提前调用了 done(),让 Gulp 误以为任务已经结束,而实际上内部的 copyPath 异步流还在后台运行。
问题根源
Gulp 判断任务完成的逻辑很明确:
- 如果任务返回一个流,Gulp 会自动等待这个流结束才标记任务完成
- 如果用
done回调,必须在所有异步操作全部完成后调用done()
你原来的 copy_sass 里,copyPath 是异步的 src/dest 流操作,但你在调用完所有 copyPath 后立刻执行了 done(),此时文件复制还在后台进行,Gulp 就直接启动了下一个任务 css_build,自然找不到还没复制好的文件。
修复方案
有两种简单的解决方式,选你习惯的即可:
方案1:让 copy_sass 返回合并后的流(推荐)
Gulp 支持返回多个流的合并,这样它会自动等待所有流完成。我们可以用 parallel 把所有复制操作的流合并,然后返回这个合并后的流:
const { series, src, dest, parallel } = require('gulp'); // 确保引入 parallel function copy_sass() { var conponments = setup.conponments; var sassList = config.conponments.sass; var mainPath = config.path.src.sass.main; var rootPath = config.path.src.sass.root; var source = getPaths(conponments, sassList, mainPath);// get a filtered list of path var destination = config.path.tmp.sass_tmp; // 并行执行所有复制任务,返回合并后的流 return parallel( () => copyPath(mainPath + 'mixin/**', destination + 'main/mixin/'), () => copyPath(mainPath + 'settings/**', destination + 'main/settings/'), () => copyPath(rootPath + 'style.scss', destination), () => copyPath(source, destination + 'main/conponment/') )(); }; // 移除 css_build 里多余的 done(),因为已经返回了流 function css_build() { var source = config.path.tmp.sass_tmp + '**/*.scss'; var destination = config.path.tmp.css.root; return src(source) .pipe(bulkSass()) .pipe(sass()) .pipe(csscomb()) .pipe(cssbeautify({indent: ' '})) .pipe(autoprefixer()) .pipe(gulp.dest(destination)); // 删掉这一行:done(); }; function copyPath(source, destination) { return src(source) .pipe(dest(destination)); }; exports.getcss = series( copy_sass, css_build ); exports.filter = filter_tmp_sass; exports.css = css_build;
方案2:用 Promise 等待所有复制流完成后调用 done
如果你更倾向于保留 done 回调,可以把每个 copyPath 转为 Promise,等待所有 Promise 完成后再调用 done():
function copy_sass(done) { var conponments = setup.conponments; var sassList = config.conponments.sass; var mainPath = config.path.src.sass.main; var rootPath = config.path.src.sass.root; var source = getPaths(conponments, sassList, mainPath);// get a filtered list of path var destination = config.path.tmp.sass_tmp; // 将每个复制流转为 Promise,监听流的 end 事件 const copyPromises = [ copyPath(mainPath + 'mixin/**', destination + 'main/mixin/'), copyPath(mainPath + 'settings/**', destination + 'main/settings/'), copyPath(rootPath + 'style.scss', destination), copyPath(source, destination + 'main/conponment/') ].map(stream => new Promise(resolve => stream.on('end', resolve))); // 等待所有复制完成后调用 done,出错时传递错误信息 Promise.all(copyPromises) .then(() => done()) .catch(err => done(err)); };
额外提示
css_build里的done()完全多余,因为你已经返回了构建流,Gulp 会自动监听流的结束来判断任务完成,删掉它可以避免混淆。- 手动执行时正常,是因为手动操作的间隔足够让复制任务完成,但自动化的
series会立刻启动下一个任务,所以必须让 Gulp 明确等待异步操作结束。
内容的提问来源于stack exchange,提问作者Pepito
相关产品推荐
相关产品推荐

