Why do some Gulp streams “flow” by default, while

2019-02-18 23:55发布

问题:

Consider these two gulp tasks:

gulp.task('src', function(done) {
  gulp.src('docs/*')
    .on('end', function() {
      console.log('ending');
      done();
    });
});

gulp.task('dest', function(done) {
  gulp.src('docs/*')
    .pipe(gulp.dest('temp'))
    .on('end', function() {
      console.log('ending');
      done();
    });
});

Running gulp dest behaves as expected, outputting:

[12:33:15] Using gulpfile ~/Projects/gulp-exit/gulpfile.js
[12:33:15] Starting 'dest'...
ending
[12:33:15] Finished 'dest' after 13 ms

However, running gulp src only outputs:

[12:31:11] Using gulpfile gulpfile.js
[12:31:11] Starting 'src'...

The 'end' callback is never called. After a bit of debugging, I think the stream in the dest task is flowing while the stream in the source task is not.

Signaling the src task to flow explicitly by calling stream.resume():

gulp.task('src', function(done) {
  gulp.src('docs/*')
    .on('end', function() {
      console.log('ending');
      done();
    })
    .resume();
});

Gives the expected output:

[12:46:52] Using gulpfile gulpfile.js
[12:46:52] Starting 'src'...
ending
[12:46:52] Finished 'src' after 11 ms

I've seen this same mix of behaviors with plugins: gulp.dest and gulp-mocha seem to return flowing streams while gulp-logger and gulp-gh-pages do not.

Why the difference in behavior?

回答1:

The reason why this happens is because some streams have data to be read, and some do not.

gulp.src('docs/*') returns a readable stream with data for each file in docs. The end event only triggers for a readable stream once all the data has been read from the stream.

Normally you would pipe this to another stream which does that automatically, but since you aren't you would need to use:

gulp.task('src', function(done) {
  gulp.src('docs/*')
    .on('data', function() {})
    .on('end', function() {
      console.log('ending');
      done();
    });
});

Alternatively you can use the finish event, which (I think) waits until all data has been pushed into the stream (i.e. it's finished working):

gulp.task('src', function(done) {
  gulp.src('docs/*')
    .on('finish', function() {
      console.log('ending');
      done();
    });
});

Your second gulp task uses gulp.dest('temp') which returns a stream with no data, so end is triggered as soon as the stream is done processing.



回答2:

Not an answer to why, but I threw together a stream-end module to smooth out the quirks in the short term:

end = require('stream-end')

gulp.task 'logger', (done) ->
  gulp.src 'docs/*'
    .pipe logger()
    .pipe end ->
      console.log('ending')
      done()

The callback passed to end is called whether the upstream is flowing or not.