流处理完成后如何确保异步代码执行?

时间:2015-05-26 17:26:37

标签: javascript node.js asynchronous promise node.js-stream

我有一个流,我通过监听dataerrorend事件来处理,我调用一个函数来处理每个data事件。第一流。当然,处理数据的函数会调用其他回调,使其异步。那么当处理流中的数据时,如何开始执行更多代码?在流中侦听end事件并不意味着异步data处理函数已完成。

当我执行下一个语句时,如何确保完成流数据处理功能?

以下是一个例子:

function updateAccountStream (accountStream, callThisOnlyAfterAllAccountsAreMigrated) {
  var self = this;
  var promises = [];
  accountStream
    .on('data', function (account) {
      migrateAccount.bind(self)(account, finishMigration);
    })
    .on('error', function (err) {
      return console.log(err);
    })
    .on('end', function () {
      console.log("Finished updating account stream (but finishMigration is still running!!!)");
      callThisOnlyAfterAllAccountsAreMigrated() // finishMigration is still running!
    });
}

var migrateAccount = function (oldAccount, callback) {
  executeSomeAction(oldAccount, function(err, newAccount) {
    if (err) return console.log("error received:", err);
    return callback(newAccount);
  });
}

var finishMigration = function (newAccount) {
  // some code that is executed asynchronously...
}

如何确保在处理完流后调用callThisOnlyAfterAllAccountsAreMigrated

这可以用承诺来完成吗?它可以通过流完成吗?我正在使用Nodejs,因此引用其他npm模块可能会有所帮助。

3 个答案:

答案 0 :(得分:2)

正如您所说,在流上监听regexp事件本身是无用的。该流不知道或关心您使用end处理程序中的数据所执行的操作,因此您需要编写一些代码来跟踪您自己的migrateAccount状态。

如果是我,我会改写整个部分。如果您在自己的信息流中使用data事件和readable,则可以按照您的意愿一次阅读多个项目。如果是那个,没问题。如果它是30,那很好。这样做的原因是,您不会因为来自流的数据而无法正常工作。就像现在一样,如果accountStream很快,你的应用程序无疑会在某些时候崩溃。

当你从流中读取一个项目并开始工作时,取下你回来的承诺(使用Bluebird或类似的东西)并将其扔进一个数组。解决了promise后,将其从数组中删除。当流结束时,将.read()处理程序附加到.done()(基本上在数组中的每个承诺中做出一个很大的承诺)。

您还可以使用简单的计数器来处理正在进行的作业。

答案 1 :(得分:1)

使用直通(npm through2模块),我使用以下控制异步行为的代码解决了这个问题:

var through = require('through2').obj;
function updateAccountStream (accountStream, callThisOnlyAfterAllAccountsAreMigrated) {
  var self = this;
  var promises = [];
  accountStream.pipe(through(function(account, _, next) {
    migrateAccount.bind(self)(account, finishMigration, next);
  }))
    .on('data', function (account) {
    })
    .on('error', function (err) {
      return console.log(err);
    })
    .on('end', function () {
      console.log("Finished updating account stream");
      callThisOnlyAfterAllAccountsAreMigrated();
    });
}

var migrateAccount = function (oldAccount, callback, next) {
  executeSomeAction(oldAccount, function(err, newAccount) {
    if (err) return console.log("error received:", err);
    return callback(newAccount, next);
  });
}

var finishMigration = function (newAccount, next) {
  // some code that is executed asynchronously, but using 'next' callback when migration is finished...
}

答案 2 :(得分:1)

通过promises处理流时要容易得多。

here复制,使用spex库的示例:

var spex = require('spex')(Promise);
var fs = require('fs');

var rs = fs.createReadStream('values.txt');

function receiver(index, data, delay) {
    return new Promise(function (resolve) {
        console.log("RECEIVED:", index, data, delay);
        resolve(); // ok to read the next data;
    });
}

spex.stream.read(rs, receiver)
    .then(function (data) {
        // streaming successfully finished;
        console.log("DATA:", data);
    }, function (reason) {
        // streaming has failed;
        console.log("REASON:", reason);
    });