我有一个任务流,它将排队,直到使用.zip()
运算符触发信号主题。信号主体订阅当前正在运行的任务。我也试图观察任务的进度排放。
我试图做的是使用.publish()
来组织Observable任务,这样我就可以让信号Subject订阅任务的.last()
发射,从而导致出队并订阅任务一般进度排放。
这个似乎正在运作。但是,每当我查看打印出来的内容时,即使我使用.subscribe()
,看起来我的Observable工厂也会被每个.publish()
调用调用。我误解了多播是如何工作的吗?我相信.publish()
ed Observable将与工厂一起创建,并且单个实例将被共享,但在调用.connect()
之前一直很冷。
请注意调用.defer()
的{{1}}。
tasker
"use strict";
const {
Observable,
Subject,
BehaviorSubject
} = Rx;
// How often to increase project in a task
const INTERVAL_TIME = 200;
// Keep track of how many tasks we have
let TASK_ID = 0;
// Easy way to print out observers
function easyObserver(prefix = "Observer") {
return {
next: data => console.log(`[${prefix}][next]: ${data}`),
error: err => console.error(`[${prefix}][error] ${err}`),
complete: () => console.log(`[${prefix}][complete] Complete`)
};
}
// Simulate async task
function tasker(name = "", id = TASK_ID++) {
console.log(`tasker called for ${id}`);
let progress = 0;
const progress$ = new BehaviorSubject(`Task[${name||id}][${progress}%]`);
console.log(`Task[${name||id}][started]`);
let interval = setInterval(() => {
progress = (progress + (Math.random() * 50));
if (progress >= 100) {
progress = 100;
clearInterval(interval);
progress$.next(`Task[${name||id}][${progress}%]`);
progress$.complete();
return;
}
progress$.next(`Task[${name||id}][${progress}%]`);
}, INTERVAL_TIME);
return progress$.asObservable();
}
// Create a signal subject that will tell the queue when to next
const dequeueSignal = new BehaviorSubject();
// Make some tasks
const tasks$ = Observable
.range(0, 3);
// Queue tasks until signal tells us to emit the next task
const queuedTasks$ = Observable
.zip(tasks$, dequeueSignal, (i, s) => i);
// Create task observables
const mcQueuedTasks$ = queuedTasks$
.map(task => Observable.defer(() => tasker(`MyTask${task}`)))
.publish();
// Print out the task progress
const progressSubscription = mcQueuedTasks$
.switchMap(task => task)
.subscribe(easyObserver("queuedTasks$"));
// Cause the signal subject to trigger the next task
const taskCompleteSubscription = mcQueuedTasks$
.switchMap(task => task.last())
.delay(500)
.subscribe(dequeueSignal);
// Kick everything off
mcQueuedTasks$.connect();
注意您如何看到使用行<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
对tasker进行多次调用,并且调用了工厂的主体。但是,在任何进度排放发生之前,将使用下一个tasker called for N
再次调用tasker()
。输出似乎是正确的,因为TASK_ID
不会跳过任何索引,只有Task[MyTask0]
s。
TASK_ID
答案 0 :(得分:5)
在此功能中似乎不需要Observable.defer
:
// Create task observables
const mcQueuedTasks$ = queuedTasks$
.map(task => Observable.defer(() => tasker(`MyTask${task}`)))
.publish();
Defer运算符等待观察者订阅它,然后 它生成一个Observable,通常带有一个Observable工厂 功能。它为每个用户重新做这件事,所以尽管每个用户都这样做 订阅者实际上可能认为它订阅了相同的Observable 每个订户都有自己独立的序列。
你已经在这里创建了一个Observable:
// Make some tasks
const tasks$ = Observable
.range(0, 3);
在map
循环中,您为每个任务创建了一个额外的Observable ......
摆脱Observable.defer
所以函数看起来像这样:
// Create task observables
const mcQueuedTasks$ = queuedTasks$
.map(task => tasker(`MyTask${task}`))
.publish();
段:
"use strict";
const {
Observable,
Subject,
BehaviorSubject
} = Rx;
// How often to increase project in a task
const INTERVAL_TIME = 200;
// Keep track of how many tasks we have
let TASK_ID = 0;
// Easy way to print out observers
function easyObserver(prefix = "Observer") {
return {
next: data => console.log(`[${prefix}][next]: ${data}`),
error: err => console.error(`[${prefix}][error] ${err}`),
complete: () => console.log(`[${prefix}][complete] Complete`)
};
}
// Simulate async task
function tasker(name = "", id = TASK_ID++) {
console.log(`tasker called for ${id}`);
let progress = 0;
const progress$ = new BehaviorSubject(`Task[${name||id}][${progress}%]`);
console.log(`Task[${name||id}][started]`);
let interval = setInterval(() => {
progress = (progress + (Math.random() * 50));
if (progress >= 100) {
progress = 100;
clearInterval(interval);
progress$.next(`Task[${name||id}][${progress}%]`);
progress$.complete();
return;
}
progress$.next(`Task[${name||id}][${progress}%]`);
}, INTERVAL_TIME);
return progress$.asObservable();
}
// Create a signal subject that will tell the queue when to next
const dequeueSignal = new BehaviorSubject();
// Make some tasks
const tasks$ = Observable
.range(0, 3);
// Queue tasks until signal tells us to emit the next task
const queuedTasks$ = Observable
.zip(tasks$, dequeueSignal, (i, s) => i);
// Create task observables
const mcQueuedTasks$ = queuedTasks$
.map(task => tasker(`MyTask${task}`))
.publish();
// Print out the task progress
const progressSubscription = mcQueuedTasks$
.switchMap(task => task)
.subscribe(easyObserver("queuedTasks$"));
// Cause the signal subject to trigger the next task
const taskCompleteSubscription = mcQueuedTasks$
.switchMap(task => task.last())
.delay(500)
.subscribe(dequeueSignal);
// Kick everything off
mcQueuedTasks$.connect();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
希望它有所帮助。