我有一个流,我通过监听data
,error
和end
事件来处理,我调用一个函数来处理每个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模块可能会有所帮助。
答案 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处理流时要容易得多。
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);
});