可观察:跳过(用户数)

时间:2019-05-22 10:55:01

标签: javascript rxjs

我有一个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

2 个答案:

答案 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)