【问题标题】:processing highland stream chunks using async使用异步处理高地流块
【发布时间】:2016-09-23 19:01:24
【问题描述】:

我正在使用highland.js 处理文件,使用流读取两个分隔符之间的内容。我还使用async.js 依次运行一系列http 请求。

理想情况下,我想将来自 highland 的输出 x 作为第一个函数传递给 async 系列(链),以便为从流中提取的每个块执行 HTTP 请求。

这可能吗?如果可以,如何实现?

var async = require('async');
var _ = require('highland');


_(fs.createReadStream(files[0], { encoding: 'utf8' }))
        .splitBy('-----BEGIN-----\n')
        .splitBy('\n-----END-----\n')
        .filter(chunk => chunk !== '')
        .each(function (x) {
        }).done(function () {

    async.series([
        function(callback) {
            setTimeout(function() {
                console.log('Task 1');
                callback(null, 1);
            }, 300);
        },
        function(callback) {
            setTimeout(function() {
                console.log('Task 2');
                callback(null, 2);
            }, 200);
        },
    ], function(error, results) {
        console.log(results);
    });

});;

【问题讨论】:

  • 在这种情况下done 是什么?
  • 为什么x没有被传递给javascript的函数?
  • done highlandjs.org/#done 是我工作代码的后遗症,它告诉流处理完成。我可能会删除它。
  • @guest271314 - 你的意思是创建一个函数并调用它来代替 x 并将内容传递给它吗?
  • “理想情况下,我想将输出 x.done() 回调中将 x 传递给 async.series

标签: javascript node.js async.js highland.js


【解决方案1】:

您可以摆脱对eachdone 的调用。过滤后可以.toArray(callback)跟进。回调传递了一个数组,其中包含来自高地的结果。你可以这样重构

var Q = require('q');
var _ = require('highland');


_(fs.createReadStream(files[0], { encoding: 'utf8' }))
        .splitBy('-----BEGIN-----\n')
        .splitBy('\n-----END-----\n')
        .filter(chunk => chunk !== '')
        .each(asyncTasks);

function asyncTasks(x) { // here, x will be each of the results from highland
    async.series([
      // do something with x results
        function(callback) {
          console.log('Task 1');
          callback(null, 1);
        },
        // do something else with x results
        function(callback) {
          console.log('Task 2');
          callback(null, 2);
        },
    ], function(error, results) {
        console.log(results);
    });
}

here 是指向toArray 文档的链接。 toArray 使用流,就像 done 也一样。如果您有任何问题,请告诉我。

虽然老实说,我认为你最好还是使用 Promise。虽然其中一部分只是个人喜好,部分是因为它使代码更具可读性。从 what I've read 开始,异步比 Promise 性能更高,但 Promise 的好处在于您可以将结果从一个函数传递到下一个函数。因此,在您的示例中,您可以在第一部分对x 做一些事情,然后将修改后的结果传递给下一个函数,下一个函数,依此类推。当您使用async.series 时,您通过调用callback(null, result) 来完成每个函数,并且在您获得所有调用的所有结果时,直到您在系列的最后完成时才能获得结果callback。现在,您始终可以将结果保存到 async.series 之外的某个变量中,但这会使您的代码更加混乱。如果你想用 Promise 重写它,它看起来如下。我在这里使用q,但它只是您可以使用的众多承诺库之一。

    var async = require('async');
    var _ = require('highland');


    _(fs.createReadStream(files[0], { encoding: 'utf8' }))
            .splitBy('-----BEGIN-----\n')
            .splitBy('\n-----END-----\n')
            .filter(chunk => chunk !== '')
            .each(asyncTasks);

    function asyncTasks(x) { // here, x will be an array of the results from highland
      return asyncTask1(x)
              .then(asyncTask2)
              .then(asyncTask3)
    }

    function asyncTask1(x) {
      var deferred = Q.defer();

      // do some stuff

      if (// some error condition) {
        deferred.reject();
      } else {
        deferred.resolve(x); // or pass along some modified version of x
      }

      return deferred.promise;
    }

    function asyncTask2(x) {
      // same structure as above
    }

    function asyncTask3(x) {
      // same structure as above
    }

现在一些异步 API 已经开始返回 Promise,除了接受回调,或者有时代替。所以能舒服一点是件好事。 Promise 非常有用。你可以阅读更多关于他们的信息herehere

【讨论】:

  • 谢谢,我现在正在尝试。为什么 Q 更好,使用它会如何。如果它更好,我会很乐意切换,
  • 看起来 x 是所有块的数组,而不是需要传递给异步链的块。
  • 哦,好的。对不起,我误解了你的需要。我更新了代码。只是轻微的变化。现在您可以调用 each 然后传入与以前相同的函数。现在将在高地的每个结果上调用 asyncTasks。每个都消耗流,因此您无需调用done() as well
  • 也给出了使用promise的解释。对于这个特定示例来说,这不是一个非常重要的问题,但可能值得研究以备将来使用。
  • 非常感谢海登的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
  • 2014-06-01
  • 1970-01-01
相关资源
最近更新 更多