使用reactiveui + throttle调用异步方法的最佳方法是什么

时间:2014-12-23 10:23:31

标签: c# system.reactive reactiveui

我正在尝试使用Rx + ReactiveUI来解决我的第一个任务,并且正在寻找解决任务的最佳实践,显示一个输入框,一旦用户开始输入就会显示建议。

根据以下代码示例,异步加载建议的最佳方法是什么?使用Subscribe或使用Select Many?或者有更好的方法来实现这两个目标吗?

     this.SearchTerms = this.ObservableForProperty(x => x.SearchTerm)
            .Throttle(SuggestionThrottle, RxApp.MainThreadScheduler)
            .Value()
            .SelectMany(async s => await this.LoadSearchSuggestions(s));  // 1st Possibility

        this.SearchTerms.Subscribe(this.LoadSearchSuggestions);           // 2nd Possibility

1 个答案:

答案 0 :(得分:14)

您必须以任何方式致电Subscribe

Rx中的查询使用延迟评估,这意味着仅定义查询不会启动它。延迟评估允许您通过有条件地应用运算符来构建查询,仅将查询定义一次并将其存储在字段中以供日后使用,或者在调用Subscribe之前传递引用而不会产生任何副作用。

如果不调用Subscribe,您的查询将保持无效状态。

Subscribe通过将IObserver<T>传递给观察者来激活查询,或者您可以使用其重载来提供OnNextOnError和/或{{ 1}}处理程序,Rx将为您转换为OnCompleted。收到查询通知的是IObserver<T>

IObserver<T>的无参数重载在内部使用静默观察者,目的是仅为其副作用启动查询。例如,在您的情况下,如果您使用Subscribe完成加载建议的所有工作而您不需要单独的SelectMany,那么您可以通过调用无参数来启动查询过载IObserver<T>

在大多数情况下,您不应使用Subscribe的无参数重载。 Subscribe的要点是您传递给它的Subscribe(或单个处理程序)旨在导致查询的副作用。通过仅在IObserver<T>Subscribe运算符中引起副作用,查询更易于推理和维护。

但是,有一个相当常见的情况是使用Do的无参数重载是有意义的:如果查询的副作用是由异步方法引起的,那么使用Subscribe和无参数SelectMany的重载最好。

原因很简单:Subscribe是顺序组合运算符,它使您可以将异步方法作为查询中的顺序步骤调用。因此,SelectMany将取消订阅与取消异步计算联系起来。处理订阅(由调用SelectMany返回的IDisposble表示)会导致Subscribe运算符的特殊异步重载所提供的CancellationToken被发出信号消除。您的异步方法可以监视SelectMany以提前退出计算。

CancellationToken没有任何重载接受异步观察者,Subscribe返回OnNext。但即使您在Task处理程序中调用返回void的异步方法,也不会在处理订阅时发出异步方法的信号。

请注意,无论如何,您的两个代码示例都略有错误。第一个示例不需要OnNextasync关键字。如上所述,await的特殊重载接受SelectMany - 返回选择器函数,以及为该函数提供Task<T>的其他重载。你可能应该使用后者。

你的第二个例子不应该编译,假设CancellationToken返回LoadSearchSuggestions。 (除非ReactiveUI库或您引用的其他库提供了Task的重载,它接受Subscribe - 返回函数,在这种情况下,您将不得不查阅其文档。)< / p>

除非后者,并假设您的其余查询是正确的,这是您应该做的:

Task

其中this.SearchTerms = this.ObservableForProperty(x => x.SearchTerm) .Throttle(SuggestionThrottle, RxApp.MainThreadScheduler) .Value() .SelectMany(LoadSearchSuggestionsAsync) .Subscribe(); 的定义如下:

LoadSearchSuggestionsAsync

请注意,Unit代表Rx中的 void 。这是必需的,因为返回非泛型async Task<Unit> LoadSearchSuggestionsAsync(string term, CancellationToken cancel) { ... return Unit.Default; } 的异步方法不能与Task一起使用。如果您要返回实际数据,则只需将SelectMany替换为您的数据类型即可。然后,您还可以将Unit处理程序传递给OnNext并使用返回值执行某些操作,例如记录。