我有一个Observable,它在调用外部api的回调时发出。我想跳过(n)发射,其中n是可观察对象的订阅者数量。
例如:订阅第二个的订阅者应该只收到第二个发射,然后取消订阅。
跳过操作符不起作用,因为订阅数可能会更改。
https://stackblitz.com/edit/rxjs-qdnh9f
let toSkip = 0;
const source = () => {
return Observable.create((observer) => {
toSkip++;
// External API callback
const handler = (count) => () => {
observer.next(count++);
};
const interval = setInterval(handler(1), 1000)
const unsubscribe = () => {
toSkip--;
console.log('clear interval');
clearInterval(interval)
}
observer.add(unsubscribe);
}).pipe(
skip(toSkip),
take(1)
);
}
const subscription1 = source().subscribe(x => console.log('subscription1', x));
const subscription2 = source().subscribe(x => console.log('subscription2', x));
// subscription3 should emit "2" as subscription2 will unsubscribe never run
const subscription3 = source().subscribe(x => console.log('subscription3', x));
setTimeout(() => {
subscription2.unsubscribe();
}, 500);
Subscription3应该发出“ 2”,因为subscription2将在被调用之前取消订阅。
控制台上的预期输出:
clear interval
subscription1 1
clear interval
subscription3 2
clear interval
答案 0 :(得分:0)
跳过工作正常,您的第一个订阅1跳过1个值并取1(跳过0得到1) subscription3跳过3个值(0,1,2),取1(即3)。 为什么应该是2?
.pipe(
skip(toSkip),
take(1)
创建可观察源并且不再更改初始值时,将执行此部分一次。而且,toSkip后来减少也没关系,源3是使用skip 3值启动的。
还要记住,同一观察者的每个新订阅都将执行此代码
toSkip++;
// External API callback
const handler = (count) => () => {
observer.next(count++);
};
const interval = setInterval(handler(1), 1000)
const unsubscribe = () => {
toSkip--;
console.log('clear interval');
clearInterval(interval)
}
observer.add(unsubscribe);
这意味着每个新订阅都会增加toSkip。 例如,此代码还会在2个单位上增加ToSkip。
var source = source();
const subscription1 = source.subscribe(x => console.log('subscription1', x));
const subscription1_1 = source.subscribe(x => console.log('subscription1_1', x));
take(1)也会自动完成收集并取消订阅所有触发您的取消订阅事件的订阅者。 您可以使用过滤器来代替它,因为它具有动态特性,但是可以跳过,但是在可观察的集合中使用带有数据状态的变量是不好的做法。 那不是企业解决方案:
import { Observable } from 'rxjs';
import { map, skip, take, filter } from 'rxjs/operators';
let toSkip = 0;
const source = () => {
let init;
return Observable.create((observer) => {
toSkip++;
init = toSkip;
// External API callback
const handler = (count) => () => {
observer.next(count++);
console.log('count ' + count);
};
const interval = setInterval(handler(1), 1000)
const unsubscribe = () => {
console.log(' clear interval ' + toSkip);
clearInterval(interval)
}
observer.add(unsubscribe);
console.log('skip ' + toSkip);
}).pipe(
filter((x) =>
{
console.log(x + ' - ' + toSkip);
return x == init || x == toSkip
}),
take(1)
);
}
const subscription1 = source().subscribe(x => {
console.log('subscription1', x);
});
const subscription2 = source().subscribe(x => {
console.log('subscription2', x);
});
// subscription3 should emit "2" as subscription2 will unsubscribe never run
const subscription3 = source().subscribe(x => {
console.log('subscription3', x)
});
setTimeout(() => {
toSkip--;
subscription2.unsubscribe();
}, 500)
答案 1 :(得分:0)
Skip有一个静态参数,但是在这种情况下,我们应该使用动态更改的变量,因此需要更改运算符。
我们也不能在观察者创建过程中将函数命名为unsubscribe
,因为它在完成后会调用。我们无法跟踪退订的次数,因此我们可以返回一个包装好的方法来完成此操作。
https://stackblitz.com/edit/rxjs-bpfcgm-检查几种情况
import { Observable } from 'rxjs';
import { map, take, filter } from 'rxjs/operators';
const getSource = function() {
let inc = 0;
let unsubscribed = 0;
const source = () => {
inc++;
let created = inc;
let handlerCount = 0;
return Observable.create((observer) => {
// External API callback
const handler = (count) => () => {
handlerCount++;
observer.next(count++); // Emit any value here
};
const interval = setInterval(handler(1), 1000)
const complete = () => {
console.log('clear interval');
clearInterval(interval)
}
return complete;
}).pipe(
filter(() => handlerCount >= created - unsubscribed),
take(1)
);
}
const unsubscribe = o => {
unsubscribed++;
o.unsubscribe();
}
return [source, unsubscribe];
}
let [source, unsubscribe] = getSource();
const subscription1 = source().subscribe(x => console.log('subscription1', x));
const subscription2 = source().subscribe(x => console.log('subscription2', x));
// subscription3 should emit "2" as subscription2 will unsubscribe never run
const subscription3 = source().subscribe(x => console.log('subscription3', x));
setTimeout(() => {
unsubscribe(subscription2);
}, 500)