a dictionary-lookup Web service that,
given a word, asynchronously returns
an array of completions for that word
via the following method:
IObservable<string[]> Completions(string
word){ … }
Assume also that using these help-
ers, you have exposed a GUI text field
input as an IObservable<string>
to produce the value of the text field
every time the input changes, and
you have wrapped a label output as an
IObserver<string[]> to display an
asynchronous data stream of string
arrays. Then you can wire up a pipe-
line that asynchronously calls the
Completions service for every partial
word typed into the text field but dis-
plays only the most recent result on
the label:
figure 9. the switch operator.
IObservable<IObservable<T>>
switch
switch
switch
IObservable<T>
figure 10. Asynchronous call made to Completions in response to a change in the input.
IObservable<string>
Completions()
Completions()
IObservable<string[]>
figure 11. the throttle operator.
delay
TextChanges(input)
The effect of the Switch operator is
that every time another asynchronous
call is made to Completions in response to a change in the input, the result is switched to receive the output of
this latest call, as shown in Figure 10,
and the results from all previous calls
that are still outstanding are ignored.
This is not just a performance optimization. Without using Switch,
there would be multiple outstanding
requests to the Completion service,
and since the stream is asynchronous,
results could come back in arbitrary
order, possibly updating the UI with results of older requests.
This basic dictionary example can
be improved by inserting a few more
operators into the query. The first operator is IObservable<T> DistinctUn
tilChanged(IObservable<T> source),
which ensures that an asynchronous
data stream contains only distinct
contiguous elements—in other words,
it removes adjunct elements that are
equivalent. For the example, this ensures that Completions is called only
when the input has actually changed.
Second, if the user types faster
than you can make calls to the Web
service, a lot of work will go to waste
since you are firing off many requests,
only to cancel them immediately
when the input changes again before
the previous result has come back.
Instead, you want to wait at least N
milliseconds since the last change
using the operator IObservable<T>
Throttle(IObservable<T> source,
TimeSpan delay). The throttle operator samples an asynchronous data
stream by ignoring values that are
followed by another value before the
specified delay, as shown in Figure 11.
The throttle operator drops events
that come in at too high a rate; however, one can easily define other opera-