Share via


Optimizing your app's lifecycle (HTML)

When developing an app, consider these important app lifecycle events: activation, suspend, and resume. Learn about these events and important performance considerations to keep in mind when handling them.

Activate quickly

App activation refers to the first time an app is launched and initialized. The code your app executes during activation has a big impact on how quickly your app launches, so be careful about what code you execute. Let's take a look at a few ways to improve your app's activation performance.

Use the correct initialization event

When your app loads an HTML file (as described in Application loading section), two important events fire to allow the app to do some initialization: DOMContentLoaded and onLoad. For your app to complete its initialization as quickly as possible, you must know when to use these events.

  • DOMContentLoaded event

    The DOMContentLoaded event is raised after the app loads all its JavaScript and CSS files. All the referenced files are ready to be accessed (including images, although they are not guaranteed to be loaded). At this point, you can begin initializing your app (app initialization doesn't usually require loaded images).

    Tip  Use the DOMContentLoaded event to begin general app initialization.

     

  • activated event

    The activated event is raised when the app is activated. It tells the app whether it was activated because the user launched it or it was launched by some other means. Use the activated event handler to check the type of activation and respond appropriately to it, and to load any state needed for the activation.

  • onload event

    After the DOMContentLoaded event is raised and after all the images referenced by the page are loaded, the onload event is raised. If you need to process your images, this is where you do it.

Use the DOMContentLoaded event to perform global initialization of the activated event handler

After your app is launched, the platform may suspend and resume it many times before the app exits. Don't use the activated event handler to perform global initialization work, because the activated handler may be called multiple times over the lifetime of the app. Use the DOMContentLoaded event to perform global initialization.

The activated event handler does two primary things:

  1. Determine the type of activation by checking the activated event arguments and respond accordingly. Perform only the work needed to handle that type of activation.
  2. Restore the app's state. If the activation type is ActivationKind.launch, restore the app's previous state if it exists by checking the WinJS.Application.sessionState object. If it contains data, use the data to restore your app's state. Then call the WinJS.UI.processAll method to initialize the app's Windows Library for JavaScript controls.

This example shows how to handle the activated and DOMContentLoaded events:

(function () {
    "use strict";

    var app = WinJS.Application;

    function initialize() {
        // Set up global event handlers
        // Initialize custom loading UI if necessary
    }

    function activatedHandler(e) {

        if (e.detail.kind == Windows.ApplicationModel.Activation.ActivationKind.launch) {

            // Check whether session state variables are valid.
            // If so, retrieve the application data saved in the checkpoint handler

            if (app.sessionState) {
                // restore previous state from sessionState
            }

            // Check tile arguments and do any specific activation work 
            // related to those arguments. 

            // Then initialize all WinJS controls
            WinJS.UI.processAll();
        }

        if (e.detail.kind === 
              Windows.ApplicationModel.Activation.ActivationKind.filePicker) {
            // Process the file picker request.
        }       
    }

    document.addEventListener("DOMContentLoaded", initialize, false);
    app.addEventListener("activated", activatedHandler, false);
    app.start();
})();

Use an extended splash screen for long startups

The app should be ready for the user to interact with it the moment the splash screen disappears. If your app needs more time to load or if you want to show real-time loading info to users, you can create a secondary, extended splash screen by creating a vew that imitates the splash screen that Windows displays. For instructions on how to do this, see How to display a splash screen for longer.

Perform only essential work during activation

Don't do more work than you have to during activation. Some apps execute code during activation that's not needed until later. Removing unnecessary code from you activated handler can sometimes cut several seconds from your app's launch time.

A common example of executing unnecessary code is loading more state info than the app needs for activation. Instead of loading all the state needed for the entire app, load only the subset needed for the app to display its initial page.

Suspend quickly and save memory

Another important event in an app's lifecycle is suspending it. An app can be suspended when the user moves it to the background or when the system enters a low power state. When the app is being suspended, it raises the suspending event and has up to 5 seconds to save its data. If the app's suspending event handler doesn't complete within 5 seconds, the system assumes the app has stopped responding and terminates it.

The system tries to keep as many suspended apps in memory as possible so that users can quickly and reliably switch between them. But if there aren't enough resources to keep an app in memory, the app is terminated. Apps don't receive notification that they are being terminated, so your only opportunity to save your app's data is during suspension.

Save only objects that changed

Many apps re-serialize all the data used for the app, even if the data hasn't changed. This costs the app extra time to serialize and save the data, plus extra time to read and deserialize the data when the app is resumed.

Instead, we recommend that the app determine when its state has actually changed, and if so, serialize and deserialize only the data that changed.

Release expensive objects on suspend and recreate them on resume

Because the system tries to keep as many suspended apps in memory as possible, it is important to minimize the amount of memory your app uses. When an app is suspended and stays in the system's memory, it can quickly be brought to the foreground for the user to interact with, without having to display a splash screen or perform a lengthy load operation.

Certain objects, such as files and devices, occupy a large amount of memory. During suspension, an app should release handles to these objects and recreate the handle when needed. This change can reduce the amount of memory your app uses by anywhere from a few hundred kilobytes to a few megabytes, and make it less likely that the app will be terminated by the system.

Save state at times other than the suspend event

We recommend that the app save state incrementally at times other than the suspending event. That is, when a bit of state changes that the app would typically want to save when it suspends, it can just save that bit of state right away and not wait for the suspending event. This minimizes the amount of work necessary within the suspending handler.

Resume quickly

A suspended app can be resumed when the user moves it to the foreground or when the system comes out of a low power state. When an app is resumed from the suspended state, it continues from where it was when it was suspended. No app data is lost, because it was stored in memory. But the app could have been suspended for a long period of time, perhaps a number of hours.

When your app is resumed, variables and objects have the exact same state they had when the app was suspended. We recommend that you register a resuming event handler if you need to update data or objects that might have changed between the time your app was suspended and when it was resumed. You can use a resuming event handler for these purposes:

  • Check if you need to refresh data from an online source that might have changed while the app was suspended.
  • If you were offline when suspended, check whether connectivity exists on resuming, and switch into online mode. The opposite is also true, especially if the user got on an airplane while you were suspended.
  • Refresh any sensor input that you're tracking, such as the compass, orientation, or geolocation.
  • Refresh the app's layout, because the app might resume directly into a different view state than when it was suspended, even to a different resolution and scaling if the device has been connected to an external monitor, docking station, and so on, or disconnected from such. The user might also have gone to PC Settings > Ease of Access and toggled Make Everything On the Screen Bigger. You'll also get focus, visibility, and sizing related events where you might do this work already, but in any case it's a good case to test.
  • Enable or disable app bar commands and other on-canvas controls that are dependent on clipboard contents.
  • Call Windows.System.Display.displayRequest.requestActive on resuming if necessary. For example, if you make a request to keep the screen on through requestActive, you need to call requestRelease on suspending and then requestActive again on resuming.
  • Check license status for trial apps and in-app purchases if you're using expiration dates. If you're suspended, you won't get the licencechanged event, but it might fire sometime after you resume. In any case, resuming is a good time to check licenses.
  • If you're using background tasks of any kind to update app data, use resuming to refresh the app with that new state.
  • Check if there's new roaming app data that appeared while the app was suspended. Windows might queue the Windows.Storage.ApplicationData.dataChanged event if this happens so you might be able to handle it that way too.
  • If you issue tile updates or toasts while the app is running (and aren't using periodic or push notifications), think about whether to refresh those updates on resuming, including scheduled notifications.
  • If you perform data transfers that might be affected by cost-awareness on metered networks, use resuming to check the network type and respond accordingly. Note that transfers you set up using the Background Transfer API will work with this automatically while you're suspended.