To serve a page, Jaxer needs to read and parse it, handle any server-side processing, and if the DOM has been changed it needs to turn it back into HTML for processing.
Currently, it does this on every normal (non-callback) page request, and given the strengths of the core Mozilla engine, it's pretty fast at it. It does however keep track of whether there was any server-side content to process, so soon Jaxer will remember that information and — if the page hasn't changed — it will tell the web server to not even route that page through Jaxer on future requests.
Ajax applications tend to have pages that live for a long time on the browser and make many callbacks. That makes it particularly important to minimize the overhead of callback processing. During a callback, Jaxer needs to not only make available the function being called, but also all the other functions this function might need to access. In fact, Jaxer makes available all the functions that were defined on that page when the page was served out, except the ones explicitly marked with a runat attribute of "server-nocache".
To make this efficient, Jaxer caches the compiled functions in memory, being careful to separate functions defined on different pages. Of course those functions are also kept in a central store, usually a database. When a callback is received, Jaxer can immediately access the already-compiled set of functions needed to process the request. Only if Jaxer is restarted, or the request is received by a different Jaxer that has never seen those functions (or the requested version of those functions), will it go to the database to get the appropriate version of those functions and rebuild its cache.