我设计了一个API(在NodeJS中),例如,它接收用户ID列表,并访问Google Firebase的API以向这些用户发送通知。
考虑到Firebase对您可以同时发送的请求数量有一个配额限制,我缓冲了ID并将请求逐个发送到Firebase,延迟时间为2秒。这里有一些简化的示例代码供您解释:
app.post('/send-request', (req, res, next) =>{
const userIds = req.body.userIds;
const streams = userIds.map((userId) => {
return Observable
.fromPromise(fetch(`firebase url`, {
method: 'POST',
headers: ...,
body: ...
}))
.delay(2000)
.retryWhen(attempts => {
return attempts.zip(Rx.Observable.range(1, 4))
.mergeMap(([error, i]) => {
if (i > 3) {
return Rx.Observable.throw(error);
}
console.log(`Wait ${i} seconds, then retry!`);
return Rx.Observable.timer(i * 1000);
});
});
});
const stream = Observable.merge(...streams);
stream.subscribe();
});
这可以处理单个请求由许多用户组成的情况。但是,如果我的API同时收到类似的请求,它一定会失败。
因此,我希望将所有这些用户ID缓冲在队列中,此队列可以继续接收越来越多的用户ID缓冲它们,同时“排除”顶部'通过以稳定的速率向Firebase发送请求来排队。但是,我不知道如何使用RxJS。我必须使用调度程序吗?或者实际上是否比使用Rx更好的解决方案?
注意:我理解Javascript是单线程的,因此它并不完全是并发性的,我只使用了这个词,所以你可以更好地理解它。
答案 0 :(得分:0)
我认为我设法提出了一些建议,关键部分是使用Subject
发布值,然后使用zip
运算符定期发出值。如果我可以按需获取值,它会更好,但是当前的解决方案已经比我原来的方法好得多。
const subject = new Rx.Subject();
const stream = subject
.zip(Rx.Observable.interval(3000), function(a, b) { return a; });
stream.subscribe(
(x) => { console.log(`onNext: ${val}`); },
(e) => { console.log(`onError: ${e}`); },
() => { console.log('onCompleted'); });
我使用VueJS为一个小小的演示构建了一个简单的网页。
const app = new Vue({
el: '#app',
data: {
subject: undefined,
stream: undefined,
count: 0,
emitHistory: [],
disableBtn: true
},
created() {
console.log('created');
this.subject = new Rx.Subject();
this.stream = this.subject
.zip(Rx.Observable.interval(3000), function(a, b) { return a; })
// .observeOn(Rx.Scheduler.queue); // not working
this.stream.subscribe(
(val) => {
console.log(`onNext: ${val}`);
this.emitHistory.push(val);
if (val === this.count) {
this.disableBtn = false;
} else {
this.disableBtn = true;
}
},
(e) => { console.log(`onError: ${e}`); },
() => { console.log('onCompleted'); });
},
methods: {
clickHandler() {
this.count++;
this.subject.onNext(this.count);
},
clear() {
this.count = 0;
this.emitHistory = [];
}
}
});
/*
Rx.Observable
.fromArray([1,2,3])
.zip(Rx.Observable.interval(500), function(a, b) { return a; })
.subscribe(
function(x) { document.write(x + '<br \>'); },
null,
function() { document.write("complete"); });
*/
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>
<div id="app">
<button @click="clickHandler()">Click me</button>
<button @click="clear()" v-bind:disabled="disableBtn">Clear</button>
<div>
<h5>Count: {{count}}</h5>
</div>
<div>
<ul>
<li v-for="(item, idx) in emitHistory" v-bind:key="idx">{{item}}</li>
</ul>
</div>
</div>
&#13;