These are good questions.
Let me start with some of the most important principles that guide the NativeScript project.
In NativeScript, we leveraged Telerik's experience creating productivity tools for developers to create a framework for building cross-platform native mobile apps that any developer can quickly pick up and use. From the beginning, NativeScript has focused on delivering a solution that should:
- Deliver native performance;
- Optimize the development experience for web developers (especially Angular/TypeScript developers).
These principles guide the architectural decisions that we make as NativeScript evolves. Let's take a closer look at how these principles have driven our decisions around threading.
This is a powerful capability, and unique, even among alternatives like React Native and Fuse that require native code plugins and new layers of abstraction to interact with native APIs.
There is a time and a place for background threads, but putting all app code on a different thread from the UI by default clearly affects the efficiency of calling native APIs.
Yes and no.
First, for those not aware, "dropped frames" are the result of the UI thread being too busy to deliver smooth, 60fps refreshes. When an app begins to drop frames, the UI "stutters" and introduces what many developers now call " jank." It's an all too common problem in hybrid apps, and a big reason we created NativeScript in the first place.
An example of how fast, fluid and responsive apps built with NativeScript are is our marketplace demo:
A quick teaser for those who love CSS - the animations on this screen are entirely made via CSS
Not coincidentally, this is the exact same problem you'd encounter creating "raw" native apps for iOS or Android using Obj-C, Swift or Java. By default, native code runs on the same thread as native UI, so CPU-intensive operations in native code can also degrade app performance and cause dropped frames.
NativeScript, true to its billing, is behaving identically to native apps.
It follows, then, just as in native apps, the correct solution is to selectively offload CPU-intensive code to background threads so that animations and other UI-related code continue to run smoothly. True in native apps. True in NativeScript.
Okay. Cool. How do you offload to background threads in NativeScript?
NativeScript started by focusing on creating a fast and powerful single-threaded native API access layer that would deliver smooth, high-performance UI for the most common app scenarios. As discussed above, we've focused on minimizing marshalling and creating a runtime that behaves very similarly to native apps.
Now that this layer is stable and performant, the next step is to add the background thread APIs to enable selective offloading of the most CPU-intensive tasks.
Background threads in NativeScript today
"Wait? I thought you said background threads were NOT in NativeScript today."
As it turns-out, most use cases for background work are not often associated with application-specific code. They are generic use cases and usually involve http or network requests, database access, image decoding and processing, heavy IO operations and so on.
For a significant number of these scenarios, NativeScript modules and plugins already exist to do the generic work on a background thread, dispatching the output to the main UI thread when the heavy lifting is done. The out-of-the-box HTTP module, for example, uses a background thread to process network requests, as does the push-notification plugin available on NPM.
Of course, there are still uncovered scenarios when you may need to utilize a background thread for generic CPU-intensive work.
That's today. It's an advanced approach, mostly intended for plugin developers.
For the "typical" NativeScript developer, we still want to provide an API that makes it possible to do arbitrary work on background threads in a cross-platform way without writing native code. Think: " Web Workers " for NativeScript. So let's look at what's next for background threads in NativeScript.
- Access to native APIs in background threads must be limited to non-UI APIs only; all UI access must happen on the main UI thread to avoid access violation errors;
- Making too many calls to the UI thread from a background process could produce worse performance due to the marshalling taxes we discussed earlier.
So, what have we learned?
- Many common scenarios that require background thread processing are already covered by NativeScript plugins and modules.
We want your feedback!
Related Resources Header image courtesy of Marlon M