Every HTML page depends on a horde of resources, such as text files (html/js/css/etc.), images and fonts. Unsurprisingly, most of the time spent during every page initialization (and in some rare cases, its continued execution) goes to resource loading and preprocessing. Most resources require some type of preprocessing before they are ready to use - HTML/CSS/JavaScript require parsing, images require decoding, etc. Every resource needs to be read from the hard drive as well. Performing the aforementioned operations before your View starts initializing is referred to as resource preloading. Preloaded resources can give you a huge performance boost in page initialization. You can even achieve single frame initialization if you manage to preload all resources for a given page.
Most resource loading optimizations consist of finding a convenient time to load the resource in advance, for example during a "Loading" screen. There are two main ways to do that with Cohtml views:
PreloadAndCacheStylesheet
API you can ensure that all of your CSS resources are already parsed and waiting when your page starts loading. Note that Font and CSS resources are cached system-wide, meaning that all Views which share the resource will benefit.You can find example implementations of all APIs listed below in the Gameface Instaload sample
You can register fonts in advance via the cohtml::System::RegisterFont API. Calling this API will schedule a stream resource request for the font as a work job. When the work is executed your OnResourceStreamRequest
callback will be invoked. Usually, you would respond to this request with an ISyncStreamReader
implementation that will read the font from the disk. To preload the font and avoid disk reads at runtime you can read and buffer the whole file inside your ISyncStreamReader
implementation and later respond to read requests from that buffer. Fonts can be heavy memory-wise and Cohtml does cache font information for already displayed characters, so if you can't spare the extra memory overhead you can use this only during initialization then release the buffer and continue reading from disk.
This API does not guarantee that the font will be loaded by the time your page first initializes, as explained in Common pitfalls.
You can preload CSS files via the cohtml::System::PreloadAndCacheStylesheet API. Passing a CSS file to this API will trigger a corresponding OnResourceRequest
callback to load the CSS file, parse it, then cache it inside Cohtml. Once loaded, the stylesheet will stay cached in Cohtml's memory, making all future initialization of the same page or other pages that use it faster.
You can use RemoveStylesheetCacheEntry
or ClearStylesheetCache
to clear one or all pre-loaded stylesheets respectively after you are done using them.
This API does not guarantee that the CSS will be loaded by the time your page first initializes, as explained in Common pitfalls.
You can preload HTML via the cohtml::System::PreloadAndCacheHTML API.
Passing an HTML file to this API will trigger a corresponding OnResourceRequest
callback to load the html body, asynchronously parse it, then cache it Cohtml. The parsed HTML will stay cached in Cohtml's memory and will be used by all views if it's requested.
RemoveHTMLCacheEntry
and ClearHTMLCache
can be used to clear cache entries from the HTML cache. Note that removing an HTML from cache that is currently in use by a view won't free the occupied memory immediately. It will be freed after all Views finish DOM building, even if the HTML is not loaded yet.
This API does not guarantee that the HTML will be loaded by the time your page first initializes, as explained in Common pitfalls.
Preloading image resources is a fairly complicated process, which rightfully deserves its own page.
Due to Cohtml's concurrent resource parsing, there is no way to guarantee that your resource will actually be parsed by the time the page starts loading. This is true for HTML, CSS, and Font preloading APIs. Consider the following snippet, which uses CSS as an example:
System->PreloadAndCacheStylesheet("SomeFolder/common.css"); // stylesheet will start pre-loading here View->LoadURL("my_url.html"); // let's assume this page uses common.css. // ... // later on, during your engine's frame execution View->Advance(time);
In the example above, when your code reaches the View->Advance(time)
line, Cohtml might still be loading common.css
on another thread. In those types of cases Cohtml will build your page without the resource, then update it on a later Advance
call, after the resource is ready. In a similar way, a View won't start building the DOM until the HTML is fully parsed.
When no API is provided for a given resource type, you can still preload the resource contents in the memory. In straightforward implementation of this can work as follows:
ResourceHandler::AddPreloadedResource(path)
function of the instaload sample. // Store file contents in memory for (auto& it : std::filesystem::recursive_directory_iterator(m_ResourcesRoot)) { auto extention = it.path().extension(); // JS files are currently not preloadable by Cohtml, so they can be // preloaded in memory only. if (extention == ".js") { auto path = it.path().generic_string(); // Assume ReadFile is a function that fetches the contents of a file in memory auto contents = ReadFile(path); m_PreloadedResources.Emplace(path, contents); } }
void OnResourceRequest(const cohtml::IAsyncResourceRequest* request, cohtml::IAsyncResourceResponse* response) std::string path = GetPathFromRequest(request->GetURL()); // Check if resource is preloaded auto findIt = m_PreloadedResources.find(request->path); if (findIt != m_PreloadedResources.end()) { // Assume the function below passes the contents of the file // to Cohtml via the IAsyncResourceResponse API. PassFileContentsToCohtml(findIt-second, response); response->Finish(cohtml::IAsyncResourceResponse::Success); } else { // You can read the file from disk here and respond immediately, // or start some process that will eventually provide the file later on }