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.


Comments are closed