UniRx 操作符2

目录

 

Interval

TakeUntil

SkipUntil

Buffer

Throttle

Delay

Return

Timer

Sample

Timestamp

ThrottleFirst

TimeInterval

Defer

Never

Scan

Switch

StartWith

CombineLatest

Do

Merge

Materialize/Dematerialize

IgnoreElements

DistinctUntilChanged

Create

Amb

Timeout

FromEvent

Publish

RefCount

Replay

Connect

Throw

Catch

Finally

DelaySubscription

PairWise


Interval

每隔一段时间进行操作

Observable.Interval(TimeSpan.FromSeconds(1)).Subscribe(seconds =>
{
Debug.LogFormat("当前时间:{0} s", seconds);
}).AddTo(this);

输出结果为:
currentTime:11
currentTime:12
currentTime:13
...

TakeUntil

TakeUntil 订阅并开始发射原始Observable,它还监视你提供的第二个 Observable。如果第二个
Observable 发射了一项数据或者发射了了一个终止通知,TakeUntil 返回的Observable会停止发射原始
Observable并终止。

this.UpdateAsObservable()
.TakeUntil(Observable.EveryUpdate().Where(_=>Input.GetMouseButtonDown(0)))
.Subscribe(_ =>
{
Debug.Log(123);
});


输出结果为,运行之后持续输出 123,当点击鼠标左键后,停止输出 123。

SkipUntil

丢弃原始 Observable 发射的数据,直到第二个 Observable 发射了一项数据

// 条件
var clickStream = this.UpdateAsObservable().Where(_ =>
Input.GetMouseButtonDown(0));
// 监听
this.UpdateAsObservable()
.SkipUntil(clickStream)
.Subscribe(_ => Debug.Log("鼠标按过了了"));

输出结果为,点击鼠标左键之后就开始持续输出 “鼠标按过了了”

Buffer

打包操作

Observable.Interval(TimeSpan.FromSeconds(1.0f))
.Buffer(TimeSpan.FromSeconds(3.0f))
.Subscribe(_ => { Debug.LogFormat("currentTime:{0}",
DateTime.Now.Second); })
.AddTo(this);

输出结果为:
11
14
17

Throttle

仅在过了一段指定的时间还没发射数据时才发射一个数据

Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0))
.Throttle(TimeSpan.FromSeconds(1))
.Subscribe(_ => Debug.Log("一秒过后"));

输出结果为,点击鼠标后 1 秒内不在点击则输出,如果有点击则中重新计时 1 秒再输出。

Delay

延迟一段指定的时间再发射来自Observable的发射

Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Delay(TimeSpan.FromSeconds(1.0f))
.Subscribe(_ => { Debug.Log("mouse clicked"); })
.AddTo(this);

输出的结果为,点击⿏标 1 秒之后输出 mouse clicked,每次点击事件都是 1 秒之后才输出。

Return

立马返回

// 就执行⼀次,类似 set
Observable.Return("hello")
.Subscribe(Debug.Log);

输出结果为
hello

Observable.Return(Unit.Default)
  .Delay(TimeSpan.FromSeconds(1.0f))
  .Repeat()
  .Subscribe(_=> Debug.Log("arter 1 seconds"))


Timer

创建一个Observable,它在一个给定的延迟后发射一个特殊的值。

Observable.Timer(TimeSpan.FromSeconds(5.0f))
.Subscribe(_ => { Debug.Log("after 5 seconds"); })
.AddTo(this);

执行结果为,在 5 秒会后输出 “after 5 seconds”

Sample

定期发射 Observable 最近发射的数据项

Observable.Interval(TimeSpan.FromMilliseconds(50))
.Sample(TimeSpan.FromSeconds(1))
.Subscribe(_ => { Debug.Log(DateTime.Now.Second); })
.AddTo(this);

输出结果为
52
53
54
...

Timestamp

给 Observable 发射的数据项附加一个时间戳

Observable.Interval(TimeSpan.FromSeconds(1.0f))
.Timestamp()
.Subscribe(timestamp => { Debug.Log(timestamp); })
.AddTo(this);

输出结果为:
0@2018/9/19 7:49:22 +00:00
1@2018/9/19 7:49:23 +00:00
2@2018/9/19 7:49:24 +00:00
3@2018/9/19 7:49:25 +00:00
4@2018/9/19 7:49:26 +00:00
5@2018/9/19 7:49:27 +00:00
...

ThrottleFirst

throttleFirst 与 throttleLast/sample 不同,在每个采样周期内,它总是发射原始 Observable
的第一项数据,⽽不是最近的⼀一项。
throttleFirst 操作符默认在 computation 调度器器上执行,但是你可以使用第三个参数指定其
它的调度器器。
它与 Sample ⾮常类似

this.UpdateAsObservable()
.Where(_ => Input.GetMouseButtonDown(0))
.ThrottleFirst(TimeSpan.FromSeconds(5))
.Subscribe(x => Debug.Log("Clicked!"));

鼠标点击之后,立即输出 “Clicked”,输出之后的 5 秒内点击无效。

TimeInterval

将一个发射数据的 Observable 转换为发射那些数据发射时间间隔的 Observable

Observable.Interval(TimeSpan.FromMilliseconds(750))
.TimeInterval()
.Subscribe(timeInterval => Debug.LogFormat("{0}: {1}",
timeInterval.Value, timeInterval.Interval));

输出结果为
0: 00:00:00.7816660
1: 00:00:00.7619180
2: 00:00:00.7531140

Defer

直到有观察者订阅时才创建 Observable,并且为每个观察者创建一个新的 Observable

var random = new System.Random();
Observable.Defer(() => Observable.Start(() => random.Next()))
.Delay(TimeSpan.FromMilliseconds(1000))
.Repeat()
.Subscribe(randomNumber=>Debug.Log(randomNumber));

输出结果为
1790623781
67128575
913269989
2027467965
297262093
1000073077

Never

创建一个不发射数据也不终止的Observable

var never = Observable.Never<string>();
//similar to a subject without notifications
var subject = new Subject<string>();

Scan

连续地对数据序列的每一项应⽤一个函数,然后连续发射结果

Observable.Range(0, 8)
.Scan(0,(acc,currentValue)=>acc+5)
.Subscribe(xx =>
{
Debug.Log(xx);
});

输出结果为
5
10
15
20
25
30
35
40

Switch

将一个发射多个 Observables 的 Observable 转换成另一个单独的 Observable,后者发射那些
Observables 最近发射的数据项

var buttonDownStream = Observable.EveryUpdate().Where(_ =>Input.GetMouseButtonDown(0));
var buttonStream = Observable.EveryUpdate().Where(_ =>Input.GetMouseButtonUp(0));
buttonDownStream.Select(_ =>
{
Debug.Log("mouse button down");
return buttonStream;
})
.Switch()
.Subscribe(_ => { Debug.Log("mouse button up"); });

执行结果为,当按下鼠标时输出 “mouse button down” 抬起之后输出 “mouse button up”。

StartWith

如果你想要一个 Observable 在发射数据之前先发射一个指定的数据序列,可以使用StartWith 操作
符。(如果你想一个Observable发射的数据末尾追加一个数据序列列可以使⽤用 Concat 操作符。)

Observable.Return("sikiedu.com")
.StartWith("http://")
.Aggregate((current, next) => current + next)
.Subscribe(Debug.Log);

输出结果为
http://sikiedu.com

CombineLatest

当两个 Observables 中的任何一个发射了数据时,使⽤一个函数结合每个 Observable 发射的最近数据
项,并且基于这个函数的结果发射数据。

CombineLatest 操作符行为类似于 zip,但是只有当原始的 Observable 中的每一个都发射了一条数
据时 zip 才发射数据。CombineLatest 则在原始的 Observable 中任意一个发射了数据时发射一条数
据。当原始 Observables 的任何一个发射了一条数据时,CombineLatest 使用一个函数结合它们最近
发射的数据,然后发射这个函数的返回值

var a = 0;
var i = 0;
var leftStream = this.UpdateAsObservable().Where(_ =>
Input.GetMouseButtonDown(0)).Select(_ => (++a).ToString());
var rightStream = this.UpdateAsObservable().Where(_ =>
Input.GetMouseButtonDown(1)).Select(_ => (++i).ToString());
leftStream.CombineLatest(rightStream, (left, right) => left + right)
.Subscribe(Debug.Log);

执⾏行行结果为,点击⿏鼠标顺序:左 -> 右 -> 左 -> 右 -> 左 -> 左 -> 右 -> 右
则输出如下
// 左
11 // 右
21 // 左
22 // 右
32 // 左
42 // 左
43 // 右
44 // 右

Do

注册一个动作作为原始 Observable 生命周期事件的一种占位符

Observable.ReturnUnit()
.Delay(TimeSpan.FromSeconds(1.0f))
.Do(_ => { Debug.Log("after 1 seconds"); })
.Delay(TimeSpan.FromSeconds(1.0f))
.Do(_ => { Debug.Log("after 2 seconds"); })
.Delay(TimeSpan.FromSeconds(1.0f))
.Subscribe(_ => { Debug.Log("after 3 seconds"); });

输出结果为
after 1 seconds // 第 1 秒结束
after 2 seconds // 第 2 秒结束
after 3 seconds // 第 3 秒结束

Merge

var aStream = this.UpdateAsObservable().Where(_ =>Input.GetMouseButtonDown(0)).Select(_ => "A");
var bStream = this.UpdateAsObservable().Where(_ =>Input.GetMouseButtonDown(1)).Select(_ => "B");
aStream.Merge(bStream)
.Subscribe(Debug.Log);

输出结果为,点击鼠标左键则输出 “A”,点击鼠标右键则输出”B”。

Materialize/Dematerialize

Materialize 将数据项和事件通知都当做数据项发射

一个合法的有限的Obversable将调用它的观察者的 onNext 方法零次或多次,然后调用观察者的
onCompleted 或 onError 正好一次。Materialize 操作符将这一系列列调⽤用,包括原来的 onNext 通
知和终止通知 onCompleted 或 onError 都转换为一个Observable发射的数据序列列。

Dematerialize 操作符是Materialize的逆向过程,它将Materialize转换的结果还原成它原本的
形式。
dematerialize反转这个过程,将原始Observable发射的Notification对象还原成Observable
的通知。

var subject = new Subject<int>();
var onlyExceptions = subject.Materialize()
.Where(n => n.Exception != null)
.Dematerialize();
subject.Subscribe(i => Debug.LogFormat("Subscriber 1: {0}", i),
ex => Debug.LogFormat("Subscriber 1 exception: {0}", ex.Message));
onlyExceptions.Subscribe(i => Debug.LogFormat("Subscriber 2: {0}", i),
ex => Debug.LogFormat("Subscriber 2 exception: {0}", ex.Message));
subject.OnNext(123);
subject.OnError(new Exception("Test Exception"));

输出结果为
Subscriber 1: 123
Subscriber 1 exception: Test Exception
Subscriber 2 exception: Test Exception

IgnoreElements

不发射任何数据,只发射Observable的终止通知

var subject = new Subject<int>();
//Could use subject.Where(_=>false);
var noElements = subject.IgnoreElements();
subject.Subscribe(i => Debug.LogFormat("subject.OnNext({0})", i),
() => Debug.LogFormat("subject.OnCompleted()"));
noElements.Subscribe(i => Debug.LogFormat("noElements.OnNext({0})", i),
() => Debug.LogFormat("noElements.OnCompleted()"));
subject.OnNext(1);
subject.OnNext(2);
subject.OnNext(3);
subject.OnCompleted();

输出结果为
subject.OnNext(1)
subject.OnNext(2)
subject.OnNext(3)
subject.OnCompleted()
noElements.OnCompleted()

DistinctUntilChanged

var subject = new Subject<int>();
var distinct = subject.DistinctUntilChanged();
subject.Subscribe(i => Debug.LogFormat("{0}", i),() => Debug.LogFormat("subject.OnCompleted()"));
distinct.Subscribe(i => Debug.LogFormat("distinct.OnNext({0})", i),() => Debug.LogFormat("distinct.OnCompleted()"));
subject.OnNext(1);
subject.OnNext(2);
subject.OnNext(3);
subject.OnNext(1);
subject.OnNext(1);
subject.OnNext(4);
subject.OnCompleted();


输出结果为
1
distinct.OnNext(1)
2
distinct.OnNext(2)
3
distinct.OnNext(3)
1
distinct.OnNext(1)
1
4
distinct.OnNext(4)
subject.OnCompleted()
distinct.OnCompleted()

Create

使用一个函数从头开始创建一个Observable

Observable.Create<int>(o =>
{
o.OnNext(1);
o.OnNext(2);
o.OnCompleted();
return Disposable.Create(() => Debug.Log("观察者已取消订阅"));
}).Subscribe(xx => { Debug.Log(xx); });

输出结果
1
2
观察者已取消订阅

Amb

给定两个或多个 Observable,它只发射最先发射数据或通知的那个 Observable 的所有数据

传递多个Observable给 Amb 时,它只发射其中一个Observable的数据和通知:最先发送通知给 Amb 的
那个,不管发射的是一项数据还是一个 onError 或 onCompleted 通知。Amb 将忽略和丢弃其它所有
Observables的发射物。

Observable.Amb(
Observable.Timer(TimeSpan.FromSeconds(3)).Select(_ => "3 sec"),
Observable.Timer(TimeSpan.FromSeconds(10)).Select(_ => "10 sec"),
Observable.Timer(TimeSpan.FromSeconds(2)).Select(_ => "2 sec"),
Observable.Timer(TimeSpan.FromSeconds(22)).Select(_ => "30 sec"),
Observable.Timer(TimeSpan.FromSeconds(6)).Select(_ => "5 sec"))
.Subscribe(
s => Debug.LogFormat("OnNext: {0}", s),
() => Debug.Log("OnCompleted"));

输出结果为
OnNext: 2 sec
OnCompleted

Timeout

对原始 Observable 的一个镜像,如果过了一个指定的时长仍没有发射数据,它会发一个错误通知

如果原始Observable过了指定的一段时长没有发射任何数据,Timeout 操作符会以⼀个 onError 通知
终止这个 Observable。

Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(1))
.Take(10)
.Timeout(TimeSpan.FromSeconds(1.0))
.Subscribe(_ => Debug.Log("clicked"));

运⾏结果为,当一秒内不做任何操作,则会报异常。

FromEvent

将其它种类的对象和数据类型转换为Observable

transform.Find("Button")
.GetComponent<Button>()
.onClick.AddListener(() => OnClickEvent());
Observable.FromEvent(action => OnClickEvent += action, action => OnClickEvent
-= action)
.Subscribe(_ => Debug.Log("button clicked"));

输出结果为,当每次点击时,输出 button clicked

Publish

将普通的 Observable 转换为可连接的 Observable

可连接的 Observable (connectable Observable)与普通的 Observable 差不多,不过它并不会在被订阅
时开始发射数据,而是直到使⽤用了了Connect操作符时才会开始。用这种方法,你可以在任何时候让一个
Observable 开始发射数据。

var unshared = Observable.Range(1, 4);
// Each subscription starts a new sequence
unshared.Subscribe(i => Debug.Log("Unshared Subscription #1: " + i));
unshared.Subscribe(i => Debug.Log("Unshared Subscription #2: " + i));
// By using publish the subscriptions are shared, but the sequence doesn't
start until Connect() is called.
var shared = unshared.Publish();
shared.Subscribe(i => Debug.Log("Shared Subscription #1: " + i));
shared.Subscribe(i => Debug.Log("Shared Subscription #2: " + i));
shared.Connect();


输出结果为:
Unshared Subscription #1: 1
Unshared Subscription #1: 2
Unshared Subscription #1: 3
Unshared Subscription #1: 4
Unshared Subscription #2: 1
Unshared Subscription #2: 2
Unshared Subscription #2: 3
Unshared Subscription #2: 4
Shared Subscription #1: 1
Shared Subscription #2: 1
Shared Subscription #1: 2
Shared Subscription #2: 2
Shared Subscription #1: 3
Shared Subscription #2: 3
Shared Subscription #1: 4
Shared Subscription #2: 4

RefCount

让一个可连接的 Observable 行为像普通的Observable

var period = TimeSpan.FromSeconds(1);
var observable = Observable.Interval(period)
.Do(l => Debug.LogFormat("Publishing{0}", l)) //side effect to show it is running
.Publish()
.RefCount();
Observable.Timer(TimeSpan.FromSeconds(5.0f)).Subscribe(_ =>
{
Debug.Log("@@@@ subscribe @@@@");
//observable.Connect(); Use RefCount instead now
var subscription = observable.Subscribe(i =>Debug.LogFormat("subscription : {0}", i));
Observable.Timer(TimeSpan.FromSeconds(5.0f)).Subscribe(__ =>
{
Debug.Log("@@@@ unsubscribe @@@@");
subscription.Dispose();
observable.Subscribe(i => Debug.LogFormat("subscription 2: {0}",
i));

输出结果为:
// 5 秒后
@@@@ subscribe @@@@
Publishing 0
subscription : 0
Publishing 1
subscription : 1
Publishing 2
subscription : 2
Publishing 3
subscription : 3
@@@@ unsubscribe @@@@
Publishing 0
subscription 2: 0
Publishing 1
subscription 2: 1
Publishing 2
subscription 2: 2
Publishing 3
subscription 2: 3
...

Replay

保证所有的观察者收到相同的数据序列,即使它们在Observable开始发射数据之后才订阅

var hot = Observable.Interval(period)
.Take(3)
.Publish();
hot.Connect();
Observable.Timer(period)
.Select(_ => hot.Replay())
.Do(observable =>
{
observable.Connect();
observable.Subscribe(i => Debug.LogFormat("first subscription : {0}", i));
})
.Delay(period)
.Do(observable => observable.Subscribe(i =>Debug.LogFormat("second subscription : {0}", i)))
.Select(observable => Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Select(_ => observable)
.First())
.Switch()
.Do(observable => observable.Subscribe(i =>Debug.LogFormat("third subscription : {0}", i)))
.Subscribe();

输出结果为
first subscription : 1
second subscription : 1
first subscription : 2
second subscription : 2
third subscription : 1
third subscription : 2

Connect

让⼀个可连接的Observable开始发射数据给订阅者


Throw

创建一个不不发射数据以一个错误终止的 Observable

Observable.Throw<string>(new Exception("error"))
.Subscribe(_ => Debug.Log("不不会输出"), e => Debug.LogFormat("发现异常:{0}", e.Message));

输出结果:
发现异常:error

Catch

从onError通知中恢复发射数据

Observable.Throw<string>(new Exception("error"))
.Catch<string, Exception>(e =>
{
Debug.LogFormat("catched exception:{0}", e.Message);
return
Observable.Timer(TimeSpan.FromSeconds(1.0f)).Select(_ => "timer called");
})
.Subscribe(result => Debug.Log(result));


输出结果为:
catched exception:error
// 1 秒后
timer called

Finally

.注册一个动作,当它产生的Observable终止之后会被调⽤,无论是正常还是异常终止。

var source = new Subject<int>();
var result = source.Finally(() => Debug.Log("Finally action ran"));
result.Subscribe(number => Debug.LogFormat("OnNext({0})", number), () =>
Debug.Log("OnCompleted()"));
source.OnNext(1);
source.OnNext(2);
source.OnNext(3);
//source.OnError(new Exception());
source.OnCompleted();

输出结果为
OnNext(1)
OnNext(2)
OnNext(3)
OnCompleted()
Finally action ran

DelaySubscription

Debug.Log(Time.time);

Observable.ReturnUnit()
.DelaySubscription(TimeSpan.FromSeconds(1.0f))
.Subscribe(_ => Debug.Log(Time.time));

输出结果为:
0
1.000366

PairWise

 

Observable.Range(0, 10)
.Pairwise()
.Subscribe(pair => Debug.Log(pair.Current + ":" +
pair.Previous));

输出结果为:
1:0
2:1
3:2
4:3
5:4
6:5
7:6
8:7
9:8

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值