rxjs6 Transformation Operators

原文链接: rxjs6 Transformation Operators

上一篇: rxjs6 Combination Operators

下一篇: rxjs6 Filtering Operators

buffer

缓存源流的数据, 在内层发出数据时, 将外层缓存的数据发出

let s1 = interval(1000)
let s2 = interval(300)

s2.pipe(
  buffer(s1)
).subscribe(console.log)
// [ 0, 1, 2 ]
// [ 3, 4, 5 ]
// [ 6, 7, 8 ]


bufferCount

第一个参数为发送数据时的buffer长度, 第二个参数是开启新buffer时的buffer长度, 默认为null

let s1 = interval(1000)
let s2 = interval(300)

s2.pipe(
  bufferCount(3, 1)
).subscribe(console.log)


bufferTime

在指定时间内缓存数据, 可用于判断双击

let s2 = timer(0, 200)

s2.pipe(
  bufferTime(500)
).subscribe(console.log)
// [ 0, 1, 2 ]
// [ 3, 4 ]
// [ 5, 6, 7 ]
// [ 8, 9 ]


bufferToggle

传入开始和结束的流, 缓存期间的数据

//emit value every second
const sourceInterval = interval(1000);
//start first buffer after 5s, and every 5s after
const startInterval = interval(5000);
//emit value after 3s, closing corresponding buffer
const closingInterval = val => {
  console.log(`Value ${val} emitted, starting buffer! Closing in 3s!`);
  return interval(3000);
};
//every 5s a new buffer will start, collecting emitted values for 3s then emitting buffered values
const bufferToggleInterval = sourceInterval.pipe(
  bufferToggle(startInterval, closingInterval)
);
//log to console
//ex. emitted buffers [4,5,6]...[9,10,11]
const subscribe = bufferToggleInterval.subscribe(val =>
  console.log('Emitted Buffer:', val)
);

// Value 0 emitted, starting buffer! Closing in 3s!
// Emitted Buffer: [ 4, 5, 6 ]
// Value 1 emitted, starting buffer! Closing in 3s!
// Emitted Buffer: [ 9, 10, 11 ]
// Value 2 emitted, starting buffer! Closing in 3s!
// Emitted Buffer: [ 14, 15, 16 ]
// Value 3 emitted, starting buffer! Closing in 3s!
// Emitted Buffer: [ 19, 20, 21 ]

只会在鼠标抬起时发送鼠标移动的事件数据

up-dccf536db10463bcc0ed83b7dc3745817ea.png

let up = fromEvent(document, 'mouseup')
let down = fromEvent(document, 'mousedown')
let move = fromEvent(document, 'mousemove')
move.pipe(
  bufferToggle(down, () => up)
).subscribe(console.log);


bufferWhen

在内层流发送数据时将缓存的外层流输出

//emit value every 1 second
const oneSecondInterval = interval(1000);
//return an observable that emits value every 5 seconds
const fiveSecondInterval = () => interval(5000);
//every five seconds, emit buffered values
const bufferWhenExample = oneSecondInterval.pipe(
  bufferWhen(fiveSecondInterval)
);
//log values
//ex. output: [0,1,2,3]...[4,5,6,7,8]
const subscribe = bufferWhenExample.subscribe(val =>
  console.log('Emitted Buffer: ', val)
);

// Emitted Buffer:  [ 0, 1, 2, 3 ]
// Emitted Buffer:  [ 4, 5, 6, 7, 8 ]
// Emitted Buffer:  [ 9, 10, 11, 12, 13 ]
// Emitted Buffer:  [ 14, 15, 16, 17, 18 ]

expand

循环生成数据, 第一个数据会直接发出, 然后以第一个为参数, 一次调用生成函数, 生成新的数据

//emit 2
const source = of(2);
const example = source.pipe(
  //recursively call supplied function
  expand(val => {
    //2,3,4,5,6
    console.log(`Passed value: ${val}`);
    //3,4,5,6
    return of(1 + val);
  }),
  //call 5 times
  take(5)
);
/*
    "RESULT: 2"
    "Passed value: 2"
    "RESULT: 3"
    "Passed value: 3"
    "RESULT: 4"
    "Passed value: 4"
    "RESULT: 5"
    "Passed value: 5"
    "RESULT: 6"
    "Passed value: 6"
*/
//output: 2,3,4,5,6
const subscribe = example.subscribe(val => console.log(`RESULT: ${val}`));


groupBy

根据关键词分组

const people = [
  {name: 'Anna', score: 100, subject: 'English'},
  {name: 'Anna', score: 90, subject: 'Math'},
  {name: 'Anna', score: 96, subject: 'Chinese'},
  {name: 'Jerry', score: 80, subject: 'English'},
  {name: 'Jerry', score: 100, subject: 'Math'},
  {name: 'Jerry', score: 90, subject: 'Chinese'},
];

let source = from(people)
let example = source.pipe(
  groupBy(person => person.name),
  mergeMap(g => {
    return g.pipe(
      reduce(
        (pre, cur) => {
          return {
            name: pre.name,
            score: pre.score + cur.score
          }
        }, {name: g.key, score: 0}
      )
    )
  }),
)

example.subscribe(console.log);
// { name: 'Anna', score: 286 }
// { name: 'Jerry', score: 270 }


map / mapTo

映射函数, 或映射为固定值

// 1 4 9
of(1, 2, 3).pipe(map(x => x ** 2)).subscribe(console.log)
// abc abc abc
of(1, 2, 3).pipe(map(x => 'abc')).subscribe(console.log)



mergeScan

统计鼠标按下的时间

mouseDown$.pipe(
  mapTo(interval(1000).pipe(
    takeUntil(mouseUp$),
  )),
  mergeAll(),
  // 不使用scan, 每次按下鼠标时, 时间会清空
  scan((pre, cur) => ++pre, 0),
).subscribe(val => (durationElem.innerHTML = `${val}s`));

使用mergeScan

<div id="duration"></div>
<script>
  const {fromEventPattern, timer, interval, fromEvent} = rxjs;
  const {bufferToggle, mergeAll, mapTo, takeUntil, map, scan, mergeScan} = rxjs.operators;
  // reference
  const durationElem = document.getElementById('duration');
  // streams
  const mouseDown$ = fromEvent(document, 'mousedown');
  const mouseUp$ = fromEvent(document, 'mouseup');
  // accumulate time mouse held down over time
  mouseDown$
    .pipe(
      mergeScan((acc, curr) => {
        return interval(1000).pipe(
          scan((a, _) => ++a, 0),
          map((val) => val + acc),
          takeUntil(mouseUp$)
        );
      }, 0)
      // output: 1s...2s...3s...4s...
    )
    .subscribe(val => (durationElem.innerHTML = `${val}s`));
</script>


pairwise

将流式数据, 转为定长数组

let s = interval(100).pipe(take(10))
s.pipe(
  pairwise()
).subscribe(console.log)

// [ 0, 1 ]
// [ 1, 2 ]
// [ 2, 3 ]
// [ 3, 4 ]


partition

根据条件, 将数据分为满足条件的和不满足条件的两组

const observableValues = of(1, 2, 3, 4, 5, 6);
const [evens$, odds$] = partition(observableValues, (value, index) => value % 2 === 0);

// 1 3 5
odds$.subscribe(x => console.log('odds', x));
// 2 4 6
evens$.subscribe(x => console.log('evens', x));


pluck

特定属性的filter, 筛选指定的属性值

of({
  name: 'a'
}, {
  name: 'b'
}, {
  name: 'c'
}).pipe(
  pluck('name')
).subscribe(console.log)
// a b c


scan

统计鼠标点击次数, 每次有数据发出时计算累加值并输出, reduce只会在流结束时输出

  mouseDown$.pipe(
    scan((pre, cur) => ++pre, 0)
  ).subscribe(console.log)

switchAll / switchMap / switchMapTo

在新的数据到来时, 取消旧的数据流

up-b75458fb0135a5827026d3c4b8fa970b96d.png

第四个数据输出时超过了1s, 所以只要最后一个流输出四个值

up-917f04c9c7e6a4a23044e8d1cec88ade64c.png

interval(1000).pipe(
  take(3),
  map(i => interval(300).pipe(
    take(4),
    map(x => i + ' ' + x)
    )
  ),
  switchAll()
).subscribe(x => console.log('sub', x))

  switchMap(v => {
    return interval(300).pipe(
      take(4),
      map(x => v + ' ' + x)
    )
  })

window

和buffer类似, 输出的是数据流而不是数组

//emit immediately then every 1s
const source = timer(0, 1000);
const example = source.pipe(window(timer(0, 3000)));
const count = example.pipe(scan((acc, curr) => acc + 1, 0));
/*
  Window 1:
  Window 2:
  0
  1
  2
  Window 3:
  3
  4
  5
  Window 4:
  6
  ...
*/
const subscribe = count.subscribe(val => console.log(`Window ${val}:`));
const subscribeTwo = example
  .pipe(mergeAll())
  .subscribe(val => console.log(val));


windowCount

按照元素个数分割数据流

const source = interval(1000);
const example = source.pipe(
  //start new window every 4 emitted values
  windowCount(4),
  tap(_ => console.log('NEW WINDOW!'))
);

const subscribeTwo = example
  .pipe(
    //window emits nested observable
    mergeAll()
    /*
            output:
            "NEW WINDOW!"
            0
            1
            2
            3
            "NEW WINDOW!"
            4
            5
            6
            7
          */
  )
  .subscribe(val => console.log(val));


windowTime

const source = timer(0, 1000);
const example = source.pipe(
  //start new window every 3s
  windowTime(3000),
  tap(_ => console.log('NEW WINDOW!'))
);

const subscribeTwo = example
  .pipe(
    //window emits nested observable
    mergeAll()
    /*
            output:
            "NEW WINDOW!"
            0
            1
            2
            "NEW WINDOW!"
            3
            4
            5
          */
  )
  .subscribe(val => console.log(val));


windowToggle

传入开始和结束的流, 将期间的数据作为新的流

const source = timer(0, 1000);
//toggle window on every 5
const toggle = interval(5000);
const example = source.pipe(
  //turn window on every 5s
  windowToggle(toggle, val => interval(val * 1000)),
  tap(_ => console.log('NEW WINDOW!'))
);

const subscribeTwo = example
  .pipe(
    //window emits nested observable
    mergeAll()
    /*
            NEW WINDOW!
            NEW WINDOW!
            10
            NEW WINDOW!
            15
            16
            NEW WINDOW!
            20
            21
            22
            NEW WINDOW!
            25
    */
  )
  .subscribe(val => console.log(val));


windowWhen

当内层流有数据时,  将外层流转为新的流

const source = timer(0, 1000);
const example = source.pipe(
  //close window every 5s and emit observable of collected values from source
  windowWhen(() => interval(5000)),
  tap(_ => console.log('NEW WINDOW!'))
);

const subscribeTwo = example
  .pipe(
    //window emits nested observable
    mergeAll()
    /*
      output:
      "NEW WINDOW!"
      0
      1
      2
      3
      4
      "NEW WINDOW!"
      5
      6
      7
      8
      9
    */
  )
  .subscribe(val => console.log(val));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值