Reactive Programming Case Study 1 - Typeahead Search

Reactive Programming Case Study 1 - Typeahead Search

·

2 min read

In web development, typeahead search is a typical use case where reactive programming helps. typeahead_search.PNG Requirements

  • User may type keyword in a textbox for search
  • After user typing, an http requests containing the latest keyword would be sent to a server API.
  • An http request should be sent only when there are no more user typing within 200ms immediately after the previous text change.
  • A new http request should cancel the previous pending http request that are not completed yet.
  • If the user types a key in the keyword, and then immediately delete the new letter within 200ms, no new requests should be sent as the keyword doesn't really change.
  • The server API returns the http response in JSON format, and the application should show it to the user.

In this case the events are inter-related, as the future text change event may affect the previous event by canceling the http requests it sent.

To implement that in a typical OO world, we need write code to keep track of the events, their timing based on which we should either wait, send request and cancel previous requests.

While with reactive approach using rxjs lib, the solution on the front-end takes about 5 lines as below. Hooray!

fromEvent(keywordTextbox, 'change').pipe(

  // ignore the change if any further changes occur within 200ms from last change
  debounce(200),

  // we send search requests only when the keyword changes since the last one.
  distinctUntilChanged(),

  // send a new request and cancel the previous pending http requests that are not completed
  // interestingly some server side web framework would also cancel the pending request handling on server.
  // For example, .NET cancelation token is used for this purpose
  switchMap(keyword => http.get<SearchResult>(`SOME_SERVER_API_URL`, { params: { keyword } })), 

  // unsubscribe from the event stream when the host component is being destroyed.
  takeUntil(this.destroyed$)
).subscribe((searchResult: SearchResult) => {
  // logic to display search result.
})