A reader of my recent MSDN Magazine article asked what I thought about performance in Cordova apps, and here's what I wrote in response.

Performance really depends on the underlying hardware, the individual platform, and the version of the platform, because it’s highly dependent upon the quality of the app host and hardware that’s running the code.

On Windows 8.1 and Windows Phone 8.1, you’re running a native app (no webviews), and because Microsoft has put tons of perf work into the IE engine on which the app host is built, JavaScript/Cordova apps run quite well. In the perf tests I did on Windows 8.1 with JavaScript apps (see chapter 18 of my free ebook), I found that the delta from JS to C# was 6-21%, JS to C++ was 25-46%, and C# to C++ was 13-22%. This was for CPU-intensive code (and a Release build outside the debugger, of course) and thus represents the most demanding situations. If you’re primarily working with UI code in the app where the system APIs are doing the bulk of the work, I’d expect the deltas to be smaller because the time spent in UI code is mostly time spent in optimized C++.

On Android, iOS, and Windows Phone 8, Cordova apps run JS inside a Webview, and thus are very much subject to Webview performance. From what I've heard–and I haven't done tests to this effect myself–performance can vary widely between platforms and platform versions. More recent versions of the platforms, e.g. iOS 7/8 and Android 4.2 or so, have apparently improved Webview performance quite a bit over previous versions. 

In short, if you’re targeting the latest platforms, performance is decent and getting better. If you're targeting these systems, then, Cordova performance should be suitable for many types of apps, though probably not for intensive apps.

It's important to note that "performance" is not really a matter of throughput: it's a matter of user experience. I like to say that performance is, ultimately, a UI issue, because even if you don't have the fastest execution engine in the world by some benchmark measure, you can still deliver a great experience. I think of all the video games I played as a kid on hardware that was far inferior to what's probably inside my washing machine today. And yet the developers delivered fabulous experiences.

That said, running JavaScript in a Webview on platforms like iOS isn't going to match a native iOS implementation, especially with signature animations that are really hard to match with CSS transitions and such. But if you're not needing that kind of experience, Cordova can deliver a great experience for users without you having to go native.

I made a diagram that’s on http://www.visualstudio.com/explore/modern-mobile-apps-vs that tries to illustrate where Cordova falls relative to Xamarin, native, and mobile web. The vertical axis is “mobile app user experience” which includes perf as well as the ability to provide a full-on native experience like I just mentioned. 

The diagram is one way to look at the relative strengths of different cross-platform approaches. In the end, you of course have to decide what perf measures are important for your customers, do some tests, and see if Cordova will work for your project. And of course, pester the platform providers to improve Webview perf too! 🙂


My associate Brian Rasmussen released this book through Microsoft Press a few months ago: http://www.amazon.com/High-Performance-Windows-Store-Brian-Rasmussen/dp/0735682631/ref=sr_1_1?s=books&ie=UTF8&qid=1414429701&sr=1-1.

Here's the short review I wrote on Amazon:

Performance is something that's easy to talk about but difficult to do. You could say that every app could in some way perform better, but how do you really think about where to make investments? Too often, developers take an ad hoc approach, not really clear on what they're trying to accomplish. This can waste a lot of resources in areas that won't have real impact on the customer experience. In this book Brian brings years of real-world insight to the question of finding what matters, clearly defining your performance goals, and then going through the process to measure the app's present reality, making changes, and evaluating progress. And like another reviewer has said, performance information–even just what tools are available–is scattered around, and having one place to bring it all together is super-valuable. 

At 240 pages it's a concise treatment of the subject and for the price (Amazon has it at $14.13), it only takes one or two good improvements to your app to more than pay for itself!



We purposely included many talks at //build 2013 about performance because it's one area that's very important for all the apps you're creating as well as for consumers' overall experience of the system. Windows 8.1 Preview has better performance across the board, so in many ways apps just benefit without doing anything special. Then we're introducing more tooling around performance, and have more experience now at best practices for apps.

Here's a rundown of the perf-related talks from //build. Pick and choose those that are relevant to your chosen language and presentation layer:

General (including reliability):

HTML/JS

C#/VB/XAML/.NET:

C++/DirectX



As you’ve probably heard many times, the use of asynchronous APIs is a key theme in Windows Store apps to help them be “fast and fluid,” and to remain responsive to touch input and so forth. Simply said, async operations run on non-UI threads, so they don’t block the UI thread (and therefore input) while their processing is going on.

However, at some point the results from those async operations (as most of those APIs produce) do have to make their way back to the UI thread. That is, some completed handler that runs on the UI thread will be called with those results, wherein that handler processes them in some way.

For small numbers of parallel async operations, this isn’t typically a problem. Problems can arise, however, if an app kicks off many simultaneous operations within a short amount of time, such that the completed handler will at some point get pounded with each individual result. For example, let’s say you have a StorageFolder for some part of the user’s pictures library, and you call its getFilesAsync method. This is a single operation that produces a vector of StorageFile objects, so no problem there.

Now let’s say you use forEach to iterate that vector and call StorageFile.getThumbnailAsync on each one. If that folder contains 1000 files, you’ll quickly kick off 1000 background threads. This might cause the CPU usage to spike, but it’s all in the background so the UI is still responsive.

Then those thumbnail results start to come into the completed handler, where you might be extracting more information from each thumbnail or calling URL.createObjectURL to turn it into a displayable image, like so (where listItemImage is, say, some img element in a ListView):

file.getThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.picturesView).done(function (thumb) {
    var stream = MSApp.createStreamFromInputStream(thumb.contentType, thumb.getInputStreamAt(0));
    listItemImage.src = URL.createObjectURL(stream);
});

thumb.getInputStreamAt, MSApp.createStreamFromInputStream, and URL.createObjectURL are all synchronous APIs, however, and assinging an image source can trigger rerendering as well once you return from that handler. So with every callback you might be blocking the UI thread for some time as well as triggering additional UI work as a consequence. In the end, even though you’re using async APIs to do some of the work, the UI can sluggish nonetheless.

So beware of situations where you’re creating a many async operations in a short span of time, you’ll want to implement a kind of batching strategy to stretch the work out in the time domain somewhat. I don’t have any specific numbers to offer here, but in the example above, you’d want to prioritize items that are actually visible and do those first, then continue doing the work for non-visible items within some setTimeout delays.

 


To continue from my previous post, here are some additional performance tools to know about.

First is a JavaScript memory analyzer that was just put out a short time ago. Read about it here: http://blogs.msdn.com/b/visualstudio/archive/2013/01/28/javascript-memory-analysis-for-windows-store-apps-in-visual-studio-2012.aspx

Second, here are topics in docs on performance analysis:

Analyzing performance of Windows Store Apps

Timing and Performance APIs (HTML/JS)

Analyzing memory usages in Windows Store Apps (HTML/JS)

Analyzing the code quality of Windows Store apps with Visual Studio code analysis (C#, VB, C++)

 

Finally, there are two posts on the Windows 8 Developer Blog that are relevant:

How to improve performance in your Metro style app

Tackling performance killers: common performance problems with Metro style apps

 


Along with testing the functionality of your app, it's also important to do performance testing on a variety of machines to make sure that your implementation is flexible enough to handle differences in processor speeds (for work on the UI thread) and GPU capabilities (especially affecting animations and rendering). Testing on different network speeds can also be helpful if you rely on online content–testing on a slow network, for example, can reveal the need to use progress controls in key places of your app (so the user doesn't think it's just hung). It can also help reveal places where you might implement strategies to avoid progress controls altogether, such as caching page content or switching between pages just with changes in visibility and not tearing down and rebuilding pages each time.

In any case, I wanted to provide some links to resources over a few posts. Here are a few topics in the docs for starters:

Performance (Windows Store Apps) – all languages

General Best Practices for Performance – all languages

Performance Best Practices – JavaScript

Performance Best Practices – C++, C#, VB, XAML

You'll also want to look at Tool: Performance Analyzer (JavaScript), which is one of the key tools to use for this task.

More to come later on–this is probably enough for you to chew on at present!