我正在使用Rx.js处理文件的内容,为每一行发出http请求,然后聚合结果。但是源文件包含数千行,我正在重载我正在执行http请求的远程http api。我需要确保在开始另一个http请求之前等待现有的http请求回调。我一次打开批处理和执行n
个请求,但是对于这个脚本执行请求就足够了。
我有以下内容:
const fs = require('fs');
const rx = require('rx');
const rxNode = require('rx-node');
const doHttpRequest = rx.Observable.fromCallback((params, callback) => {
process.nextTick(() => {
callback('http response');
});
});
rxNode.fromReadableStream(fs.createReadStream('./source-file.txt'))
.flatMap(t => t.toString().split('\r\n'))
.take(5)
.concatMap(t => {
console.log('Submitting request');
return doHttpRequest(t);
})
.subscribe(results => {
console.log(results);
}, err => {
console.error('Error', err);
}, () => {
console.log('Completed');
});
但是,这不会串行执行http请求。它输出:
Submitting request Submitting request Submitting request Submitting request Submitting request http response http response http response http response http response Completed
如果我删除对concatAll()
的调用,则请求是串行的,但我的订阅函数在http请求返回之前看到了observable。
如何以串行方式执行HTTP请求,以便输出如下?
Submitting request http response Submitting request http response Submitting request http response Submitting request http response Submitting request http response Completed
答案 0 :(得分:1)
这里的问题可能是当你使用rx.Observable.fromCallback
时,你在参数中传递的函数会立即执行。返回的observable将保留稍后传递给回调的值。为了更好地了解正在发生的事情,您应该使用稍微复杂的模拟:对您的请求进行编号,让它们返回您可以通过订阅观察到的实际(每个请求不同)结果。
我在这里发生了什么:
take(5)
发出5个值map
发出5条日志消息,执行5个函数并传递5个observables concatAll
处理,这些可观察对象发布的值将按预期顺序排列。你在这里订购的是调用函数的结果,而不是对函数本身的调用。为了实现您的目标,您只需在rx.Observable.fromCallback
订阅它而不是在创建时调用您的可观察工厂(concatAll
)。为此,您可以使用defer
:https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/defer.md
所以你的代码会变成:
rxNode.fromReadableStream(fs.createReadStream('./path-to-file'))
.map(t => t.toString().split('\r\n'))
.flatMap(t => t)
.take(5)
.map(t => {
console.log('Submitting request');
return Observable.defer(function(){return doHttpRequest(t);})
})
.concatAll()
.subscribe(results => {
console.log(results);
}, err => {
console.error('Error', err);
}, () => {
console.log('Completed');
});
您可以在此处看到类似的问题,并提供了一个很好的解释:How to start second observable *only* after first is *completely* done in rxjs
您的日志可能仍会连续显示5条“提交请求”消息。但是你的请求应该按照你的意愿一个接一个地执行。