The code in an app defines its behavior. Understanding how your app executes its code can help you improve its performance.
How your app executes code
Two of the most important things to know about how your app executes code is that app code is event driven and all components share the same thread.
- Event driven
The Windows Store app using JavaScript platform is event-driven. This means that your code executes only when it's triggered by an event (the only exception is that code may also be executed at parse time).
- Single threaded
The Windows Store app using JavaScript platform is single-threaded. This means that all components of the platform run on the same thread, including both the UI and JavaScript code execution, and only one piece of code can execute at a time. The only way to run your code in another thread is to use web workers. Web workers create a parallel thread used only for JavaScript code execution. In Windows 8, CPU cycles are taken away from background apps and given to the foreground app so that it can provide a more responsive UI.
The platform executes the code for each event in the queue one at a time, as shown in this illustration:

The illustration shows that the platform is currently processing a touch event handler, while a timer event, a postMessage event, and another timer event wait in the queue to be processed. When code for one event handler is executing, the platform can't respond to any new events. If a new event takes place while the touch event handler code is executing (suppose the user touches another item on the screen), the new touch event handler can't be executed until the current one completes. If the initial touch event handler code is long running, there is a delay between the user's interaction and your app's response, resulting in a sluggish response times.
There are ways to avoid these performance pitfalls. The next sections describe some of them.
Avoid running code that takes a long time to execute
When the user interacts with an app by touching the screen and you handle the interaction in an event, the app can't respond to the next user interaction until your code for the first event handler finishes. To ensure your app stays responsive, you can use these techniques to execute your code:
-
Use Web Workers to move execution to another thread
If your code takes a long time to execute, move it to a Web Worker. By using Web Workers an app can define a set of code to execute in another thread, separate from the main thread. One example of a good use of Web Workers is to calculate the computer's move in game where the user is playing against it. Typically, the code that calculates the computer's next move takes a lot of time to execute. If this code is executed on the main thread, the app can't respond to additional interactions from the user until the code finishes executing. Instead, the app can move the logic to a Web Worker to execute the logic on a different thread, and then inform the main thread after the computation is complete.
Tip While an expensive (long-running) operation is taking place on the main thread of the app, no other events can be processed. So, offload expensive work to a Web Worker. Some operations, such as calculating the next move in a game, take a long time to execute and can delay responses to other events.
- Use setImmediate to execute code on the UI thread
Another tool that can help keep your app responsive is the setImmediate function. Use this function to define a callback method that executes when the platform has finished processing all events and made display updates.
Although the setImmediate function provides a way to execute code on the UI thread when no other events are waiting to be processed, it doesn't prevent new events from taking place while executing the callback. So, don't use the setImmediate function to execute expensive code. Use it only to perform quick operations without interfering with events that might have already been queued.
Although setImmediate can help an app more efficiently execute code on the UI thread, over-use of setImmediate can cause performance issues. Between queued setImmediate calls, execution could be yielded to the host, potentially allowing expensive operations such as a layout pass to take place. For this reason, we recommend that you batch related updates, such as UI updates, into a single setImmediate call.
- Avoid creating timers than run for less than 10ms
When you specify a time of less than 10ms for a timer function (such as setTimeout), the system must load additional binaries to achieve the timer. Loading the extra binaries can degrade performance, so, when possible, avoid creating timers that run for less than 10ms.
Use asynchronous APIs
To help keep your app responsive, the platform provides asynchronous versions of many of its APIs. An asynchronous API executes in the background and informs the app after it's completed by firing an event. When calling an API from the main thread, use the asynchronous version if it's available.
One common example of a useful asynchronous API is XMLHttpRequest, which is a networking API. It lets an app initiate a request to a remote server. The time it takes to complete the request is unknown. This example executes an open operation asynchronously by passing true to the XMLHttpRequest.open function to execute asynchronously.
var xhr = new XMLHttpRequest(); xhr.onload = function(){ // The request completed }; xhr.onerror = function(){ // The request failed with an error }; xhr.open("GET", "mysite.com/page.aspx", true); xhr.send(null);
When the code in the example executes, the main thread begins a background request to the specified URL and then continues executing other code. After the request completes, it raises the load event. Your app can handle the event to process the XMLHttpRequest results.
If the example passed a value of false to the XMLHttpRequest.open function instead, the JavaScript engine would block any other code from executing until the XMLHttpRequest completed.
Tip When executing code on the main thread, use asynchronous APIs when they're available. When you use a synchronous API, all other code execution on the main thread is blocked until the API completes, so the app can't respond to new events while the API is executing.
Cancel ongoing requests where appropriate
Requests, such as networking requests, are easily initiated, yet often forgotten. It's common for an app to initiate a network request and not cancel it after it's no longer needed.
This often happens when apps implement the search contract and listen for the change event on the search box. Some apps must perform a network request to get results for the user, and initiate the request when the event fires. But often the app overlooks the previous search request: if there was a previous search request, it's no longer needed and should be cancelled.
Most expensive APIs, such as FileReader or XMLHttpRequest, provide a way to cancel the operation. By canceling, the app can regain those resources that would have been used to complete the operation.
Build date: 11/29/2012