简体   繁体   English

为什么我的已发布的延迟Observable工厂被多次调用?

[英]Why is my published deferred Observable factory being called multiple times?

I have aa task stream that will queue until a signal Subject is triggered using the .zip() operator. 我有一个任务流,它将排队,直到使用.zip()运算符触发信号主题。 The signal subject subscribes to the currently running task. 信号主体订阅当前正在运行的任务。 I am trying to also observe the progress emissions of the task. 我也试图观察任务的进度排放。

What I have tried to do is use .publish() to multicast the task Observable so that I can allow the signal Subject to subscribe to the .last() emission of the task to cause a dequeue and also subscribe to the tasks general progress emissions. 我试图做的是使用.publish()来组织任务Observable,以便我可以允许信号主体订阅任务的.last()发出以导致出队并且还订阅任务一般进度排放。

This seems to be working. 似乎有效。 However, whenever I look at what is printed out, it looks like my Observable factory is getting called by each .subscribe() call even though I used .publish() . 但是,每当我查看打印出来的内容时,即使我使用.publish() ,看起来我的Observable工厂也会被每个.subscribe()调用调用。 Am I misunderstanding how multicasting works? 我误解了多播是如何工作的吗? I believed the .publish() ed Observable would be created with the factory and that singular instance would be shared, but cold until .connect() was called. 我相信.publish() ed Observable将与工厂一起创建,并且单个实例将被共享,但是直到调用.connect()才会冷。

My Task Runner 我的任务亚军

Notice the .defer() that calls tasker . 注意调用tasker.defer()

 "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> 

My Output 我的输出

Notice how you see multiple calls to tasker with the line tasker called for N and that the body of the factory is called. 请注意如何使用tasker called for N调用的行tasker called for N查看对tasker的多次调用,并tasker called for N工厂的主体。 However, before any progress emissions happen, tasker() is called again with the next TASK_ID . 但是,在任何进度排放发生之前,将使用下一个TASK_ID再次调用tasker() The output seems correct because Task[MyTask0] doesn't skip any indices, only TASK_ID s. 输出似乎是正确的,因为Task[MyTask0]不跳过任何索引,只跳过TASK_ID

tasker called for 0
Task[MyTask0][started]
[queuedTasks$][next]: Task[MyTask0][0%]
tasker called for 1
Task[MyTask0][started]
[queuedTasks$][next]: Task[MyTask0][20.688413934455674%]
[queuedTasks$][next]: Task[MyTask0][32.928520335195564%]
[queuedTasks$][next]: Task[MyTask0][42.58361384849108%]
[queuedTasks$][next]: Task[MyTask0][73.1297043008671%]
[queuedTasks$][next]: Task[MyTask0][100%]
tasker called for 2
Task[MyTask1][started]
[queuedTasks$][next]: Task[MyTask1][0%]
tasker called for 3
Task[MyTask1][started]
[queuedTasks$][next]: Task[MyTask1][37.16513927245511%]
[queuedTasks$][next]: Task[MyTask1][47.27771448102375%]
[queuedTasks$][next]: Task[MyTask1][60.45983311604027%]
[queuedTasks$][next]: Task[MyTask1][100%]
tasker called for 4
Task[MyTask2][started]
[queuedTasks$][next]: Task[MyTask2][0%]
tasker called for 5
Task[MyTask2][started]
[queuedTasks$][next]: Task[MyTask2][32.421275902708544%]
[queuedTasks$][next]: Task[MyTask2][41.30332084025583%]
[queuedTasks$][next]: Task[MyTask2][77.44113197852694%]
[queuedTasks$][next]: Task[MyTask2][100%]
[queuedTasks$][complete] Complete

Looks like Observable.defer is unnecessary in this function: 在这个函数中看起来像Observable.defer是不必要的:

// Create task observables
const mcQueuedTasks$ = queuedTasks$
  .map(task => Observable.defer(() => tasker(`MyTask${task}`)))
  .publish();

The Defer operator waits until an observer subscribes to it, and then it generates an Observable, typically with an Observable factory function. Defer运算符等待观察者订阅它,然后它生成一个Observable,通常带有Observable工厂函数。 It does this afresh for each subscriber, so although each subscriber may think it is subscribing to the same Observable, in fact each subscriber gets its own individual sequence. 它为每个订户重新执行此操作,因此尽管每个订户可能认为订阅了相同的Observable,但实际上每个订户都获得其自己的单独序列。

You've already created an Observable here: 你已经在这里创建了一个Observable:

// Make some tasks
const tasks$ = Observable
  .range(0, 3);

Within the map loop you're creating an extra Observable for each task... map循环中,你为每个任务创建了一个额外的Observable ......

Get rid of Observable.defer so the function would look like this: 摆脱Observable.defer所以函数看起来像这样:

// Create task observables
const mcQueuedTasks$ = queuedTasks$
 .map(task => tasker(`MyTask${task}`))
 .publish();

Snippet: 片段:

 "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> 

Hope it helps. 希望能帮助到你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我的代码被多次调用? - Why is my code being called multiple times? 为什么我的处理程序被多次调用? - Why is my handler being called multiple times? 为什么我的GreaseMonkey函数被意外地多次调用? - Why is my GreaseMonkey function unexpectedly being called multiple times? 为什么我的HTTP获取请求被多次调用? - Why is my HTTP get request being called multiple times? 为什么我在 React 中的组件被多次调用? - Why is my component in React being called multiple times? 为什么多次调用 fetchDashboard 函数 - Why fetchDashboard function is being called multiple times 为什么在多次调用设置新$ .Deferred的函数时将我的延迟对象设置为已解析而不是挂起? - Why is my deferred object set to resolved instead of pending when calling a function that sets a new $.Deferred multiple times? 为什么我的 eventListener 被多次调用 - why is my eventListener called multiple times 为什么我的spritesheet被多次加载? - Why is my spritesheet being loaded multiple times? 当几个“ then”处理程序链接到一个延迟的处理程序时,为什么要调用多个“ fail”处理程序? - Why are multiple 'fail' handlers being called when several 'then' handlers are chained to a deferred?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM