在节点流管道内运行一次功能

时间:2016-03-24 23:57:31

标签: node.js stream

我正在使用vinyl-fs编写一个简单的管道来加载markdown文件,将它们转换为HTML,并将它们保存到磁盘。这一切都有效。

但是,在我pipe()链的中间,我想执行一个异步任务,该任务应该只对我的所有文件进行一次。我当前的问题涉及加载文件(文件在链中间加载很重要),但这是一个问题,我发现自己一直在磕磕绊绊。

为了解决这个问题,我已经开始这样做了:

vfs.src(*.md).pipe(function() {

  var loaded = false;

  return through2.obj(function(file, enc, cb) {
    if(!loaded) {
      fs.readFile('myfile', function(err, data) {
        // use data for something
        loaded = true;
        cb(null, file);
      }
    } else {
      // passthrough
      cb(null, file);
    }
  });
}

这感觉有点傻。我接近这一切都错了,或者这实际上是一件好事吗?

1 个答案:

答案 0 :(得分:0)

在阅读了大量关于节点流的文章后,似乎最好的实现方法是监听流finish事件,然后根据前一个流中的文件创建一个新流。这允许我完全按照我想要的方式执行:通过管道传输文件,直到我需要访问某些任务的文件数组,然后继续管道流。

以下是这样的:

var vfs = require('vinyl-fs');
var through = require('through2');

// array for storing file objects
var files = [];

// start the stream
var firstStream = vfs.src("*.jpg")

  // pipe it through a function that saves each file to the array
  .pipe(through.obj(function(file, enc, cb) {
    files.push(file);
    console.log('1: ', path.basename(file.path));
    cb(null, file);
  }))

  // when this stream is done
  .on('finish', function() {

    console.log('FINISH');

    // files will now be full of all files from stream
    // and you can do whatever you want with them.        

    // create a new stream
    var secondStream = through.obj();

    // write the files to the new stream
    files.each(function(file) {
      secondStream.write(file);
    });

    // end the stream to make sure the finish
    // event triggers
    secondStream.end();

    // now continue piping
    secondStream.pipe(through.obj(function(file, enc, cb) {
      console.log('2: ', path.basename(file.path));
      cb(null, file)
    }))
    .pipe(vfs.dest("tmp"));
  });

在这种情况下,我的脚本旁边有5张JPG图片,而console.log会说

1:  IMG_1.JPG
1:  IMG_2.JPG
1:  IMG_3.JPG
1:  IMG_4.JPG
1:  IMG_5.JPG
FINISH
2:  IMG_1.JPG
2:  IMG_2.JPG
2:  IMG_3.JPG
2:  IMG_4.JPG
2:  IMG_5.JPG