如何从async.parallel&转换系列到可组合的Promises?

时间:2015-09-29 02:18:03

标签: node.js asynchronous stream promise bluebird

我正试图从异步过渡到承诺,这就是我所拥有的。如果代码看起来很人为,那是因为我将其从我正在处理的内容中简化出来,以便更容易掌握。我正努力让Promise.all执行。

我注释掉了我想在promises中实现的异步代码:

var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs-extra'));
var path = require('path');
var tar = require('tar-fs');

module.exports = Archive;

function Archive() {
  var self = this;
  var self.base_dir = '/bar/baz',
  var self.file1 = 'foo/file1',
  var self.file2 = 'foo/file2',
  var self.file3 = 'foo/file3',
  var self.file4 = 'foo/file4'
}

Archive.prototype.make = function(done) {
  var self = this;
  // async.series([
  //     function(next) {
  //       self._prepareFilesDir(next);
  //     },
  //     function(next) {
  //       self._copyFiles(next);
  //     },
  //     function(next) {
  //       self._writeArchive(next);
  //     }
  // ], done)
  self._prepareFilesDir().bind(self)
    .then(self._copyFiles.bind(self))
    .then(self._writeArchive.bind(self))
    .catch(function(e) {
      return done(e);
    });
};

// ********************************
// * Private functions
// ********************************

Archive.prototype._prepareFilesDir = function() {
  var self = this;
  return fs.emptyDirAsync(self.base_dir);
};

Archive.prototype._copyFiles = function() {
  var self = this;
  var sources = {
    file1: path.resolve('baz', 'file1'),
    file2: path.resolve('baz', 'file2')
    file3: path.resolve('baz', 'file3')
    file4: path.resolve('baz', 'file4')
    file5: path.resolve('baz', 'file5')
  };
  var destinations = {
    file1: path.resolve(self.base_dir, self.file1),
    file2: path.resolve(self.base_dir, self.file2),
    file3: path.resolve(self.base_dir, self.file3),
    file4: path.resolve(self.base_dir, self.file4),
    file5: path.resolve(self.base_dir, self.file5)
  };

  var filters = {
    qux: /^qux/,
    bru: /^bru/,
    blerg: /blerg$/
  };

  function copyFile1() {
    console.log('hello world');
    return fs.copyAsync(sources.file2, destinations.file1, { filter: filters.qux });
  };
  function copyFile2() {
    return fs.copyAsync(sources.file2, destinations.file2);
  };
  function copyFile3() {
    return fs.copyAsync(sources.file3, destinations.file3, { filter: filters.bru });
  };
  function copyFile4() {
    return fs.copyAsync(sources.file4, destinations.file4, { filter: filters.blerg });
  };

  return Promise.all([
      copyFile1,
      copyFile2,
      copyFile3,
      copyFile4
  ]);

  // async.parallel([
  //   copyFile1(next),
  //   copyFile2(next),
  //   copyFile3(next),
  //   copyFile4(next)
  // ], function(err) {
  //  if (err) return done(err);
  //   done(null);
  // })
};

Archive.prototype._writeArchive = function() {
  var self = this;
  var archive_dir_path = path.resolve(self.base_dir, '..');
  var tarPromise = function() {
    return new Promise(function(resolve, reject) {
      tar.pack(self.files_path)
        .pipe(fs.createWriteStream(archive_dir_path + '.tar'))
        .on('error', reject)
        .on('finish', resolve)
    });
  };

  fs.ensureDirAsync(archive_dir_path)
    .then(tarPromise);
};

我必须做错事,因为你好世界'永远不会打印。我认为这个流是正确的,但我也不太确定。我的转换基于promise-nuggets.github.io片段。

我如何做Promise.all?我希望保留单独的功能,因为我认为这有助于更好地理解代码。

谢谢,

2 个答案:

答案 0 :(得分:1)

我发现的错误:

  • make方法中,只有在出现错误的情况下才会调用done,建议删除done回调,只返回promise
  • 再次在make,您正在_prepareFilesDir().bind(self),因为州长bind此时是多余的,此时应该是call/apply
  • _writeArchive
  • ,你需要返回promise,否则它将返回undefined并假设async函数已经完成。

    更新fiddle

  • 中的代码

答案 1 :(得分:0)

@ mido22修复了几个问题。还有一个问题,在Pormise.all()中,函数不应该作为引用传递,而是执行。

var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs-extra'));
var path = require('path');
var tar = require('tar-fs');

module.exports = Archive;

function Archive() {
  var self = this;
  var self.base_dir = '/bar/baz',
  var self.file1 = 'foo/file1',
  var self.file2 = 'foo/file2',
  var self.file3 = 'foo/file3',
  var self.file4 = 'foo/file4'
}

Archive.prototype.make = function() { // CHANGED
  var self = this;
  // async.series([
  //     function(next) {
  //       self._prepareFilesDir(next);
  //     },
  //     function(next) {
  //       self._copyFiles(next);
  //     },
  //     function(next) {
  //       self._writeArchive(next);
  //     }
  // ], done)
  return self._prepareFilesDir() // CHANGED
    .then(self._copyFiles.bind(self))
    .then(self._writeArchive.bind(self)); // CHANGED
};

// ********************************
// * Private functions
// ********************************

Archive.prototype._prepareFilesDir = function() {
  var self = this;
  return fs.emptyDirAsync(self.base_dir);
};

Archive.prototype._copyFiles = function() {
  var self = this;
  var sources = {
    file1: path.resolve('baz', 'file1'),
    file2: path.resolve('baz', 'file2')
    file3: path.resolve('baz', 'file3')
    file4: path.resolve('baz', 'file4')
    file5: path.resolve('baz', 'file5')
  };
  var destinations = {
    file1: path.resolve(self.base_dir, self.file1),
    file2: path.resolve(self.base_dir, self.file2),
    file3: path.resolve(self.base_dir, self.file3),
    file4: path.resolve(self.base_dir, self.file4),
    file5: path.resolve(self.base_dir, self.file5)
  };

  var filters = {
    qux: /^qux/,
    bru: /^bru/,
    blerg: /blerg$/
  };

  function copyFile1() {
    console.log('hello world');
    return fs.copyAsync(sources.file2, destinations.file1, { filter: filters.qux });
  };
  function copyFile2() {
    return fs.copyAsync(sources.file2, destinations.file2);
  };
  function copyFile3() {
    return fs.copyAsync(sources.file3, destinations.file3, { filter: filters.bru });
  };
  function copyFile4() {
    return fs.copyAsync(sources.file4, destinations.file4, { filter: filters.blerg });
  };

  return Promise.all([
      copyFile1(), // execute functions
      copyFile2(), // idem
      copyFile3(), // idem
      copyFile4()  // idem
  ]);

  // async.parallel([
  //   copyFile1(next),
  //   copyFile2(next),
  //   copyFile3(next),
  //   copyFile4(next)
  // ], function(err) {
  //  if (err) return done(err);
  //   done(null);
  // })
};

Archive.prototype._writeArchive = function() {
  var self = this;
  var archive_dir_path = path.resolve(self.base_dir, '..');
  var tarPromise = function() {
    return new Promise(function(resolve, reject) {
      tar.pack(self.files_path)
        .pipe(fs.createWriteStream(archive_dir_path + '.tar'))
        .on('error', reject)
        .on('finish', resolve)
    });
  };

  return fs.ensureDirAsync(archive_dir_path)
    .then(tarPromise);  // CHANGED, 
};