Client-side Search: Facebook & Remember The Milk
by Yun Huang Yong on July 29, 2009
A previous post discussed image pre-loading and its impact on user perceived performance. In this post we’ll highlight a technique used by Facebook and Remember The Milk which implements search functionality entirely on the client (browser) side.
Traditionally we’re used to search as a server side function. You visit Google, enter your query and Google’s hundreds of thousands of machines collaborate to produce the most relevant results from the web. Searching billions of documents within 200 milliseconds is pretty impressive by any standard but despite Google’s exemplary efforts there’s a limit to how fast a server-side search can be given that a network connection is still involved.
But what if the dataset being searched is relatively small? Is there a need to run all searches on the server or could it be done in the user’s browser?
Facebook implements client side search in at least two areas: the global site search in the top right hand corner, and the Inbox search. Both of these search fields use a pre-loading technique which loads the user’s entire friend list in a single HTTP request when the user clicks into the search field. This saves Facebook from sending out unnecessary bytes if a user never performs any searches, yet still minimises the user’s wait time as the required data would most likely have finished loading behind the scenes whilst they are typing their query.
The data sizes involved are surprisingly small too. With 226 friends the raw Javascript encoded version of my friend list is about 39kB but with gzip compression it arrives over the network as 10kB. Additionally Facebook sets an Expires: header advising that my friend list can be stored for 1 week so unless my browser fills its cache I should be fetching this 10kB no more than once a week.
Remember The Milk goes a step further by including the user’s entire task list and associated metadata within the initial HTML load of the user’s home page.
The search box is then implemented as:
<form onsubmit="control.updateListFilter(); return false;" action="">
The result is that searches are near instantaneous as they execute entirely within the browser. This is a huge boost to usability, especially for a time/task-management application.
The most obvious question then is how large a user’s task list might get, and the resultant impact on the initial load times of the user’s home page. If you consider a user with 1,000 tasks, and each task is roughly 500 bytes of raw JSON, then the initial page load is at least 500kB heavier but with gzip compression this would reduce to around 100kB of added weight.
However with 10,000 tasks the compressed data size approaches the megabyte mark. Whether this technique still improves the user experience really depends on the user’s usage habits, though I suspect that if a user has 10,000 tasks in RTM they would probably be quite happy about trading off a longer initial load time for the ability to very quickly filter their monster task list. :-)
Finally, with the entire task list loaded in browser there is the issue of updates – what happens when a user adds, modifies, or deletes a task?
A POST is performed to ensure the server state reflects the user’s changes, and Javascript is returned which updates the in-browser state. The following is a Firebug Net view of an “Add Task” operation:
