13.4. Multi-Stage DownloadDownload, Incremental, Multi-Stage, Parallel Figure 13-8. Multi-Stage Download13.4.1. Developer StoryDave's been informed an e-commerce homepage is turning many users away with its absurdly slow initial download. He refactors it so the initial download is nothing more than a banner and the key navigation links. News and featured items are still on the page, but they're pulled down separately, after the initial page has loaded. 13.4.2. ProblemHow can you optimize downloading performance? 13.4.3. Forces
13.4.4. SolutionBreak content download into multiple stages, so that faster and more important content will arrive first. Typically, the page is divided into placeholders (e.g., div elements) with the content for each placeholder downloaded independently. XMLHttpRequest Calls can be issued simultaneously or in a serial sequence, and the page will gradually be populated as the calls return. The pattern applies when an application needs to download a lot of content from the server. Typically, this occurs on startup and also when a major context switch occurs. By breaking up the call, you can deliver faster and more important data earlier on. You avoid bottlenecks that occur when a single piece of content blocks everything else from returning. The initial download of a page might be very small, containing just a skeleton along with navigation links and enough context to help the user decide if it's worth sticking around. That's the critical content for a fresh visitor, and there's no need to make him wait for the rest of the page to load. The browser can request the main page content as a separate call. This pattern is in some respects an Ajaxian upgrade of the old technique of filling up a page gradually, where the server continues flushing the buffer and the user can see the page as it loads. Ajax makes the whole thing more powerful, because the latter downloads can attach to any existing part of the page. One resource risk is having too many requests at once. Thus, consider a (purely speculative) Multiplex Call variant. Establish a browser/server protocol that lets the browser wrap multiple requests and the server wrap multiple responses. Then, issue only a single call with all required data inside. The immediate response might return a few results only, so the browser waits a bit, and then makes a further request for outstanding data. The whole process repeats until the browser has all the data. 13.4.5. Decisions13.4.5.1. How will the page be divided into blocks?The trickiest decision is how to divide the page into blocks, each of which will be downloaded individually. Since the blocks are downloaded in parallel, the main advice is to create small blocks of initial content to ensure the initial download is quick, and to group together content that's likely to be ready at the same time. Also, too many blocks will give the initial load an ugly appearance and may have the undesirable effect of causing already displayed elements to move around. For a fresh visitor, one example would be to create blocks as follows:
Some of these may be combined too, as it's important to avoid too many blocks. So you might have a single request to retrieve both navigation and general information, which is then split and painted onto separate blocks. Note that this doesn't have to apply to a homepageif you are offering Unique URLs, visitors can jump into an Ajax App at different points, so the main page content might actually be quite "deep" into the application. 13.4.5.2. How will the page be structured?Ideally, this pattern should not affect the page appearance, but will require some thinking about the underlying HTML. In particular:
13.4.5.3. What happens to the blocks while their content is being downloaded?The entire DOM itself can be established on the initial load, so that divs and other structures are used as placeholders for incoming content. If that's the case, most of those elements can be left alone, but if the user is waiting for something specific that may take some time, it would be worth placing a Progress Indicator on the block where the output will eventually appear. It's also possible to construct the DOM dynamically, so that new elements are added as new content arrives. This approach may be more work, but it may help to decouple the browser and the server. With the right framework in place, it means that the browser does not have to know exactly which items will be downloaded. The browser might ask the server to send all adverts, and the sender simply responds by sending down an XML file with three separate entries, which the browser then renders by adding three new divs. 13.4.5.4. Will the calls be issued simultaneously?Let's say you're at a point where you suddenly need a whole lot of content. Should you issue several requests at once? Not necessarily. Keep in mind there are limits on how many outgoing requests the browser can handle at one time and consider what's best for the user. If there's a bunch of content that might not be used, consider deferring it for a bit with a JavaScript setTimeout call. That way, you can help ensure the user's bandwidth is dedicated to pulling down the important stuff first. 13.4.6. Real-World Examples13.4.6.1. KayakKayak (http://kayak.com) is a travel search engine. You tell it where you're going, and it then searches through many online travel sites to build up a set of options for you. While waiting for a search query, the results page initially shows just the site banner, the search you entered, and a Progress Indicator (Figure 13-9). As the results for each external site arrives, Kayak adds the site name and whatever flights it found there. The flights aren't just appended, but kept in sorted order. You also have the option to finish the search by clicking an Enough Results button. Figure 13-9. Kayak Progress Indicator13.4.6.2. NetVibesNetVibes (http://netvibes.com) is an Ajax portal that launches parallel XMLHttpRequest Calls on startup, one for each Portlet. Many portals follow this pattern. 13.4.6.3. TalkDiggerTalkDigger (http://talkdigger.com) is an Ajaxian meta-search for web feeds. Traditional meta-searches usually output results to the browser as they're received from individual engines, so the results page isn't well-ordered. With TalkDigger, each individual search engine gets its own div on the page. As the results come in, they're placed on the right spot. 13.4.7. Code Example: AjaxPatterns PortalThe code example is a portal demo (http://ajaxify.com/run/portal) that downloads content in various stages (Figure 13-10):
Figure 13-10. Multi-Stage Download Portal demoThe initial HTML contains the header and placeholders for the content that will be injected. There's an initial Loading message for each of these: <h1>ajax patterns Portal demo</h1> <a href="http://ajaxpatterns.org">Ajax Patterns Wiki</a> | <a href="http://ajaxify.com">Ajax Demos</a> | <a href="http://ajaxpatterns.org/Ajax_Examples">Ajax Examples</a> <div > </div> <div > <div >Loading ...</div> <div > </div> <div >Loading ...</div> </div> <div >Loading ...</div> The side links and main content are loaded immediately on page load, and sent to a callback function that morphs the corresponding div: window.onload = function( ) { ajaxCaller.get("sideLinks.html", null, onServerResponse, false, "siteLinks"); ajaxCaller.get("allPatterns.phtml", null, onServerResponse, false, "allPatterns"); ... } function onServerResponse(html, headers, elementId) { $(elementId).innerHTML = html; } A few seconds laterprobably after all the content has been loadedthe ad content is requested: window.onload = function( ) { ajaxCaller.get("sideLinks.html", null, onServerResponse, false, "siteLinks"); ajaxCaller.get("allPatterns.phtml", null, onServerResponse, false, "allPatterns"); setTimeout("ajaxCaller.get('ad.html',null,onServerResponse,false,'ad')", 5000 } 13.4.8. Alternatives13.4.8.1. All-In-OneAs was mentioned, the alternativeand the de facto choiceis to download everything in one go. 13.4.9. Related Patterns13.4.9.1. PortletPortlets (Chapter 15) are good candidates for content-specific downloads. A portal's overall structure can be downloaded initially, and each Portlet's content then be downloaded (and refreshed) in parallel to the rest of the page. 13.4.9.2. GuesstimateWhile a block is waiting to be loaded, you might populate it temporarily with a Guesstimate (see earlier). 13.4.9.3. Progress IndicatorWhile a block is waiting to be loaded, you might populate it temporarily with a Progress Indicator (Chapter 14). 13.4.9.4. On-Demand JavaScriptLike Multi-Stage Download, On-Demand JavaScript (Chapter 6) involves an initial download followed by further downloads later on. That pattern focuses specifically on JavaScript content rather than display and semantic content. It's also about downloading only when needed. The emphasis here is on downloading according to an initial schedule. Other patterns, such as Microlink and Live Search, cover on-demand downloading of display and semantic content. 13.4.10. MetaphorMulti-Stage Download mirrors agile project management. If you can deliver some really useful things early on, why hold off until everything else is ready? |