The page lifecycle in Jaxer has two parts: Jaxer processes pages before they are served to the browser, and Jaxer processes calls from the browser back to server-side functionality. Let's examine the second part: how Jaxer makes it easy for the browser to call back server-side functions.
Let's start with the simplest example. If we were writing a purely browser-side app, we could write:
When you see the page in the browser it has a single button, and when you click it you get an alert of "42". To get the data from the server instead, just add a runat attribute to the script tag, with a value of "server-proxy" ("server" to execute the code on the server, "proxy" to make it callable from the browser):
How does this work? When Jaxer first processes a page, before sending it to the client, it executes any JavaScript code designated to run at the server: specifically, any script blocks with a runat attribute of "server", "both", or one of their variants. You can designate some of the functions defined during that processing to be available for callbacks. These functions are only available for callbacks from this page.
How is a function designated as callable from the browser? If it's in a script block with a runat="server-proxy" attribute, or if it has a "proxy" property with a value of true, or if it's included in the Jaxer.proxies array in the page. If any of these holds, the function is cached (saved) on the server at the end of page processing, and in its place a proxy function with the same name is injected into the browser-bound page. When the proxy function is called, on the browser, it makes an XMLHttpRequest back to Jaxer; Jaxer retrieves the original function and executes it; then the result is returned to the browser, where it's handled as if the proxy function returned it.
In fact, there are two proxy functions injected into the browser-bound page for every callable server-side function: one with the same name as the server-side function, and one with "Async" appended to its name. The second one is used to make asynchronous calls, ones that don't freeze the browser while the request is made to the server, processed, and returned. The Async version takes an additional first argument: a function to be called when the response is received from the server. That function takes as its arguments the returned result of the server-side function.
Here's an example:
Note that calling the getLastName() function on the server is as easy as calling any function on the browser — because there actually is a getLastName() function on the browser, and it's a proxy for the true getLastName() function on the server. Using getLastNameAsync() requires a bit more work restructuring your code to allow for the asynchronous flow, but it often means a better user experience.
In many cases, other functions are needed on the server during a callback. For example, let's say getLastName() requires certain access privileges. It needs to call a getCurrentUser() function and then call isAuthorized() on it. But getCurrentUser() and isAuthorized() should not be callable from the browser directly, e.g. for security reasons. To achieve this, Jaxer automatically caches any other functions defined at the end of page processing (unless they're explicitly designated with runat="server-nocache" or runat="both-nocache"), and makes them available to other functions — but not to the browser — during a callback (we omit the asynchronous version for simplicity):
All three server-side functions getCurrentUser(), isAuthorized(), and getLastName() are saved after the page is processed and are available during a callback; but only one, getLastName(), is allowed to be called directly from the browser, and it can then call the others as needed. It's a good practice to limit the proxied functions to only the ones actually needed by the browser to support the user interaction flow.
To understand callbacks in even more detail, consider the page lifecycle. Jaxer loads the page and processes it, creating the DOM from the HTML and running the server-side JavaScript, which may create some functions and may manipulate the DOM. At the end of the page the HTML DOM is turned back into HTML, and that is sent to the browser. Jaxer then caches whatever functions may be required during a callback, destroys the server-side global "window" JavaScript context and all the JavaScript functions and data in it as well as the DOM, and prepares for its next request. The cached functions are saved to the database, but for efficiency they're also cached as bytecode in memory (on that one Jaxer instance). Then on every callback, an empty "window" object with an empty DOM is made available, and the cached functions for that page are recreated in that window (using the bytecode in memory, after fetching from the database if needed). Finally, the specific function specified in the callback is executed. (We're skipping details about versioning of the functions, packaging data from and to the browser, handling exceptions, and so on.)
As a result of this flow, you can see that the environment available during a callback isn't the same as during the initial page. Basically, just the cached functions are available. In most cases, that works well, and is highly efficient: there's no need to recreate the entire original page to call a function, no complications trying to somehow sync the DOM during the callback to the possibly-changed DOM now on the browser, and no danger that user-specific data on that page may be available to other users, etc. But sometimes you need more control, e.g. to make a server-side library available. If that server-side library consisted purely of functions, it was probably automatically cached when loaded during the initial page processing, so everything just works. But if it requires some non-function objects to be present, you'll need to recreate those yourself during the callback. How do you do that? The easiest way, if that library is contained an external JavaScript file, is to load it via <script src="myLibrary.js" runat="server" autorun="true"></script>. The autorun attribute tells Jaxer to automatically run this library not only on every request for this page but also on every callback on this page; for efficiency, the library is actually compiled into bytecode and stored in memory (on that Jaxer instance). Alternatively, you can define a special function called oncallback in your page. This special function will be executed on every callback for this page, before the function you're calling back is executed. Your oncallback() can e.g. check whether the environment is set up, and if not it can do so. To see this in more detail, see the FAQ entry on oncallback().