From what I understand everything runs on the primary thread. So this is a feature request -- but if done possible sooner would eliminate any later incompatibilities. Having the main thread run the interface and JS runtimes means that hiccups can and will occur frequently. Either the design where the interface is run on its own thread; and the engine is on its own or the ability to start webworks will eliminate these types of issues where you need to do any long running calculations.
Please vote for this feature in our ideas portal.
Yeah, I'm pretty sure ReactNative does something along those lines at the moment. Even if JS is in its own thread, I still think that having something like a WebWorker would be very useful feature to have.
+1 I made a comment about this on the Q&A blog post and didn't get a respond. I think this is important to, especially when animation or long background task comes into play. I hope other upvotes this feature. It very important for performance.
+1
My reply was originally posted on the forums but I'm reposting it here is well:
_This is really a tough engineering problem to solve as there is no silver bullet here. For example we can introduce WebWorkers but they do have their flaws as well. There is this new re-thinking of WebWorkers in the web space - SharedWorker that tries to solve some of the limitations there. There are other concept like immutable data structures that are slowly gaining momentum._
_I also want to mention that React Native solution has its own flaws. Being always on a separate thread means that you will constantly have to marshall data (in their case serializing/deserializing JSON) between the JS thread and the UI thread. This might be beneficial for compute intensive JavaScript but in the general case the price you pay is significantly higher compared to doing it in the UI thread._
_In order for us to provide the right solution we need your use cases. What is your particular scenario that you need to perform compute intensive JavaScript operations? Having more use cases on the table will help us drive this forward._
Persoanlly, more I'm a fan of the code running in the UI thread by default. I just think that having the option to run things in a worker would be a useful feature to have for projects that would need a separate thread for heavy computations and what not. But even more so, it'd be nice if we had an abstraction that would let us write something like and Android Service which would let our JS code run even when it's not part of the UI of an app.
My top case isn't even necessarily compute intensive, but that I have a
background operation that isn't tied to an Android activity but still
needs to run. Maybe I have a messaging app that receives pushes from a
server, a location tracker that performs activities based on where the
device is, etc. In Android, the only way to reliably run code separate
from the visible UI is in a service. It'd be nice if Nativescript could
encapsulate that idea somehow into some cross-platform concept,
something like a headless block of code with a lifecycle and the ability
to communicate with other blocks. Not familiar with WebWorkers but
perhaps their semantics could be adopted and translated to Android
services, whatever the IOS equivalent is, etc.
+1 to what @ndarilek is saying. I think that ServiceWorker is a better abstraction than WebWorkers for this case, though. Since WebWorkers are more like a separate thread and must be started by the UI, where as a ServiceWorker can run even when a website isn't even opened.
Sometimes you don't get a preference as to whether or not a long-running
task can execute on the UI thread. As an Android user who relies on
accessibility, I can tell you that actions that block the UI thread can
murder accessibility. Say you're displaying a splash screen to notify a
visual user that a long-running action is taking place. As a blind user,
I don't know that is happening unless I touch the screen to learn of it.
If your long-running action is happening on another thread, then the
accessibility service can get the UI details from the app and report the
screen's message to me. If it is blocking, the service hangs and throws
an ANR, or sometimes crashes out-right. I doubt the Android a11y
developers see this as a bug because developers are urged to run
intensive tasks on another thread, and indeed not doing so is a
StrictMode policy violation. I can almost always spot apps that don't
spin off threads for long-running actions--until recently, one of my
fitness trackers didn't do so, and I usually took several attempts to
launch it because it'd block communicating with the server and I'd touch
the screen too quickly.
All that is to say that moving long-running tasks into another thread
isn't usually a matter of developer preference. It's a platform best
practice whose violation has consequences for some users. That said, I
recognize this is a difficult problem and don't have a solution to
propose. That's probably why we don't see lots of these types of
scripting environments on mobile platforms years after they've surfaced. :)
I posted a response to that email thread but for simplicity here are basically my two use cases:
The only reason I suggested "WebWorkers" is because those doing development on the Web are probably already familure with them. All I just want some sort of background thread.
Hi everyone,
I looked at the documentation (perhaps I did it wrong) and saw nothing about multi-threading too. This thread is actually quite new so I was simply wondering the status of this request?
Thanks a lot. Can't wait to see all NativeScript possibilities.
Regards.
Hi @VinceOPS, this issues is still not in active development. We treat it with high priority and we are evaluating what will be the best strategy here based on all the feedback.
Can you please share your scenario that requires multithreading.
Thanks!
Hi @valentinstoychev. Understood!
The typical scenario would be any common background task like fetching some data from a webservice (which could eventually timeout) or a database. Inserting group of rows in a database, too. Generating a .CSV file (sent, later, by email) with few hundred or thousands or entries...
I hope it helps.
Thanks!
Regards.
Thanks @VinceOPS - this helps a lot!
@ligaz
This might be beneficial for compute intensive JavaScript but in the general case the price you pay is significantly higher compared to doing it in the UI thread.
Thing here is that React's JS computations is heavy, this is why they went native and on separate thread by default. Here, for {N} is not real need to be by default on separate thread, but having ability to run system thread with JS handling would be good since without it smooth UI is hard thing (see how hard it's for mobile web to live on one thread).
Anything new on this one?
Image/Bitmap processing is one more thing that could be done in background.
@cime Bitmap decoding is already on a background thread if you are using our http/fetch module to download a picture. For 1.4.0 we will try to move all image decoding operations in the background no matter where the picture is loaded from.
Sorry, I wasn't clear. I mean custom bitmap processing like rotations etc.
Ideally I would like to have something like this:
var backgroundTasks = require("background-tasks");
backgroundTasks.doInBackground(function() {
// my JS code here
// return data;
}).then(function(data){
// data = result that you return from callback above
}).catch(function(exception) {
// exception = native exception or exception that you throw in callback
});
A few use cases I need to cover and would ideally (or necessarily) handle off the UI thread.
Web socket communication with a server to update a local cache of the database the user needs access to, which would be updated in diffs (on child added/changed/removed events), then scheduling cleanup operations to trim or update the oldest accessed items in the local cache. The UI thread would only interact the local cache in this scenario.
Custom image/file processing, such as cropping a photo before uploading, or reading image EXIF data.
Background service to sip GPS data over time while the app is not open and send that data to the server, potentially executing callbacks based on proximity to geo-fencing data.
Think the others have hit most of my pain points ready, so I'll add a +1 for image processing/manipulation as a function that can be intensive and tends to be a bit of a blocker.
+1 Database processing.
+1 gps/Beacon radio access
+1 network access
+1 xml/json parsing
All have aspects that get intense and cause blocking
To me, network and database access would be the items that are the most likely to have an impact on the UI thread (thus causing _hiccups_ when doing intensive processes)
Could one hypothetically just use the Java Thread class? Or would that cause issues since v8 runs javascript single threaded?
:+1:
@RangerMauve sadly the java Thread class is a no go. It still executes the run method on the main thread. Sames goes for android.os.AsyncTask
:+1: on this. Even though the response to network calls is async, the work involved in issuing the requests is enough to make our UI too slow to use, particularly on Android, where doing anything in an onNavigatedTo callback blocks the navigation, which isn't a problem on iOS so much.
Would this feature also include the the ability to create background service in Android? Like using the
IntentService?
@pacal, No, this request is to allow the ability to create threads in the running application so that you can move long running tasks into a thread. For example; if I'm doing some serious image processing; you don't want the interface to hang while it is happening. By sticking it into a thread; it works but leaves your application responsive.
A service is a different beast all together (even though you can use it for some tasks like a thread)
@NathanaelA Ok. that is what i presumed. However issue #2 which is what appears more in line of what I am thinking makes reference to this issue. That does not seem right. From what I understand now then is that NS does not support creating a background process application in either IOS or Android.
@pacal you do want #2 -- Since you are looking for a service. And yes you are correct, currently NativeScript does not support background services either...
Just curious, but is this issue due to the fact that Javascript is single threaded and the complexity to spawn new threads for processes and tie it all together for NS to work is non-trivial? Comparing with React for a bit, they really just have 2 threads working, is this not something NS could implement? 1 main UI thread and a single "processing" thread?
Disclosure: full iOS/Android dev amateur here, just trying to figure out advantages vs disadvantages...
Guys,
No way to implement a backgroud thread in {N} ?
@pierrediderot - this is a big Depends. ;-) You can create Java and ObjectiveC plugins that spawns additional threads and does work in those threads. However, currently the JS engine does not support it. What this request is for is to allow your JavaScript code to create a thread so you can have some of your own JS code do some work in the background.
@pierrediderot I can say that this is an interesting problem, at least on Android platform. For example, Android services run on the main thread so you get all callbacks (e.g. onCreate
, onStartCommand
, etc.) executed on the main thread. On the other hand, all calls through the binder are executed on an arbitrary thread from the binder thread pool. How are we going to share state (a common and useful pattern) inside a single service instance? A message passing comes to mind, but are you really willing to use such programming model? Another option, which we already use, is to serialize/dispatch all operations onto a given thread.
These are all good questions. In our team, we've been discussing them for some time. The good news is that we've stabilized, so to say, the runtime and now is a good time to provide the first iteration of the multithreading support. I strongly encourage anybody who is interested in this feature to take part in this discussion. You can help with a comment or if you prefer you can write a technical spec. Keep in mind that the technical details of a given implementation are not so important here (though they are important for the performance), but what matters is whether the suggested programming model is easy to comprehend and unambiguous.
@slavchev I think the webworker model would probably be the easiest and best implementation; JavaScipt by its own nature is single threaded. So me spinning up another thread to do work is really what I need. We are all used to how the browser does it (at least those of us who have used Webworkers) and about the only complaint I have is some browsers you have to convert data to JSON -- if NativeScript allowed me to do either raw copies between VM's or even potentially "dangerous" transfers (i.e. if I send a variable to the other VM, I have to know that I shouldn't use that variable in the current vm) of a variable without having to turn it into JSON that would be awesome...
I think that more than just webworkers for separate threads, it'd be useful to have something akin to ServiceWorker which can be run as a service in order to handle push notifications. Ideally it'd have the same API as the browser so that it'd be completely cross-platform.
@RangerMauve, I think that is actually a separate issue #2. The issue I raised was to allow background threads. #2 is dealing with background services. Their is some overlap; but to make NS work as a Background service I believe requires quite a bit more work to the NS runtimes than just enabling background threads...
As @NathanaelA said the two scenarios are similar but different. Web workers are excellent for parallel tasks that requires no (or minimal) synchronization. We are going to implement them, that's for sure. Of course, they have their price and specifics. For example, you have to be careful when you use modules in web workers. Our modules are not designed with web workers in mind. I guess nothing good will happen if you do require('application')
inside a web worker. Of course, there is no meaning to require the application module again but we shouldn't forget that modules can include other modules and sometime this cascading effect might not be obvious. This doesn't mean that web workers are bad or dangerous. There are plenty of scenarios where they are useful. For example, if you want to encrypt a string then web workers are good tool. Message based communication for this scenario is the right choice.
In any case we have some work to do. It's not a single front, say only the runtimes, but we have to think about the "web worker readiness" of our modules as well. Don't get me wrong. I am not talking some extensive analysis here or redesigning all modules. But providing at least some practical error/warning message will do the job for the first iteration. We know that we won't get it right from the first time. We will do what everybody does - provide these features as experimental ones for a few releases until we stabilize the APIs.
I've just been learning NativeScript today and I've only read about and played a little bit with ReactNative (so take what I say with a grain of salt), but I wanted to add something I'd heard about ReactNative that esp. relates to this comment by @ligaz above:
I also want to mention that React Native solution has its own flaws. Being always on a separate thread means that you will constantly have to marshall data (in their case serializing/deserializing JSON) between the JS thread and the UI thread. This might be beneficial for compute intensive JavaScript but in the general case the price you pay is significantly higher compared to doing it in the UI thread.
I wanted to say aside from issues of performance/responsiveness, have people seen how you can actually debug react-native apps using chrome developer tools? And even if the app is running on an actual device?
I was really fascinated when I heard that it seemed kind of magical to me they could do that. Until I read how it's architected with the javascript part and the native part behaving like a client and server running in parallel communicating with one another using (as the quote above says) a JSON protocol.
I thought that was really clever, so normally the app would run these two parts (the javascript thread and the native thread) together in a deployed app, but for development and debugging they can get this super quick REPL-like ease of instantly editing and changing things on the fly with instantaneous feedback.
To me that's a bigger benefit than concerns over responsiveness of the UI (which might or not arise in a particular app but the ease of editing and debugging applies to all apps!)
I say this partly because I liked a lot of what I saw in NativeScript (I was doing that groceries tutorial) but the biggest shortcoming I felt was that for me the build times were pretty slow, and even the "livesync" was somewhat slow (and unreliable for me in the iOS simulator). And I'm on a pretty good Macbook Pro... is it just me I wonder? Is building and livesync slow for other people?
If so I thought maybe that would be a reason to consider something similar to what react-native has done. Maybe for NativeScript could it mean that the "bridged"/"proxied" calls to the native routines would be treated (in effect) like rpc calls? With the goal of being able to truly do like react-native and run the javascript in the browser with chrome developer tools for development/debugging?
That to me would really make the development experience much nicer if it were possible.
I think this might be where I'd read some of this about react-native btw - also he has videos there showing how he's able to make changes that instantaneously show up in an opengl view:
Hi, what if there are 2 javascript threads? can we add another javascript background thread? so its like nativescript + react native javascript (which is in background)
@x4080 had a brilliant idea in #1376, now it doesn't actually solve the issue in this request; but it does potentially give us a way to work around this issue in a lot of use cases. It is a way to actually generate another usable JS thread. I have confirmed the idea works on Android 4.4; and I suspect it would also work on iOS. Anyone up for helping build the plugin to support this, switch over to #1376 and lets discuss it....
+1
Ok, since this issue (i.e. adding native nativescript threads) is still a long ways off before it is implemented; the idea that @x4080 has, so intrigued me that I had to write the android side of the plugin last Friday. :grinning: I'll probably work on the iOS side of the plugin sometime this week. This does NOT replace what I want in this issue; but it does actually mitigate/work around it somewhat as the new nativescript-webworkers project actually allows me a more threads to do stuff in. So for those who need more threads; their is a way to do it fairly easily now!
@NathanaelA, is the annotation thing solved?
@x4080 -- didn't need to use annotation for what I did. Looked at the code; and it probably would work, but using that code added complexity and a security hole I didn't need.
Ok ill take a look
Good job, and the data passing is between js in webkit into the webworker in webkit right? not communicating outside with android/nativescript, if we want to communicate to outside, we still need the annotation thing for lollipop up, or there s something i missed ?
No, the code I wrote wrap the functionality to talk between NativeScript and your code inside the WebView. In NativeScript you create a new WebWorker; and that webworker runs inside a newly created WebView. The interface is identical to a HTML WebWorker for simplicity. :grinning:
You don't need any annotations for the way I used to do the communications. And it should work on everything Android 4.0 and up. This is fully functional without you having to do anything additional beyond adding the plugin and using it like any other normal HTML webworker...
Oh thats cool :)
Ok so, I finished wiring up WKWebView today to use on iOS; and it appears that if it isn't attached to a view it doesn't actually run anything JS. Ergh... Apparently UIWebView does work when detached; so I might switch to that even though the performance isn't as good. Not sure... This might take a little bit longer to figure out which way to go for iOS...
@NathanaelA , nice work, BTW the using JavaScript for another thread limitation is we cannot share variables, everything must be json parsed first
@x4080 - that is the expected behavior. WebWorkers never share anything. You have to postMessages between them to send any data between them.
Status update; the webworkers project is done and released for both iOS and Android. ;-) It does allow you to have multiple threads; the threads DO NOT have access to NativeScript stuff, so it is limited in that regard -- But it is a full JS thread.
NativeScript guys; the NativeScript-WebWorkers project does NOT replace what I want in this issue; it does give us a work around in some cases; but having a full NativeScript background thread would allow me to have things like the my SQLite plugin be completely in the background. Please keep this feature up high in the to be done list, as it is still the third most requested feature in NS.
Or maybe there's some kind of bridge/ documentation to make it easier to integreate native code with NS, like in react native?
@x4080 - There is no way at all for my implementation of WebWorkers to actually talk directly to the underlying native platform functions like NativeScript does.
But just to make sure you aren't misunderstanding. The Webworkers, CAN EASILY communicate with your own code in NativeScript (and vis-versa); but they just cannot call any Android or iOS Native platform code (i.e. like Java.xxx or NSString), this is the limitation I am talking about.
If you need access to the native platform functions from your webworker, you would need to send a message from the webworker to the NativeScript side, the NS side would handle the native call(s) and then return the results back to the Webworker. This is identical to the modal that Browsers use; if the WebWorker needs to do anything with a page/dom it has to communicate back to the main javascript engine thread. Then the main thread can return values to the WebWorker.
@x4080 - Re-reading your question; I'm not 100% sure I answered it. NativeScript already can talk to the underlying platform without any bridge code having to be made. This is the primary reason why it is (imho) so vastly superior to React-Native.
The ability for a second thread is the only thing that I personally think React has "technologically" better going for it; but if you compare feature for features; based on everything else; that single feature is not enough of a win, to even come close to make me switch platforms. (And I expect NS will get this feature sometime this year as it is the third most requested feature).
i agree, thats why i stick to ns :). my comment actually not directed to this thread but for ns as a general. If we can add native language easily, it will be easy for multi thread
And the bridge is not perfect either. I tried to inherit widget view and it crashes. Ios has some limitation as well i think
You can only send POD (plain old data) over the bridge (i.e. anything you could send via a JSON object over the internet to a remote server). You can't send a component. The two sides are two totally different JS VM's and so a native reference won't work. I suspect that even once the "official" threading system is done, this will be also a limitation to simplify multi-threading. If you read any of the documentation on WebWorkers in browser you will see this is the expected behavior. The bridge to communicate is used only to send actual POD data; you do you work and return POD back.
+1
+1
@enchev @atanasovg
I took the animation-demo and made some screen captures showing the issue with not having access to a background thread:. ;-)
If you have nothing going on; it should look like this (which is nice and smooth!):
If you add anything that causes a bit of work on the main thread you see this:
If you add anything that causes a lot of work on the main thread you see this:
ALL of these are recorded at 30 frames per second. You are seeing exactly what I see.
Animations are pretty pointless if you are doing any type of real work at that moment in the application. Having the ability to spin off any work into other JS threads would allow us to fix this issue. This is the visible effect to too much work going on; which is WAY WAY worse than RN or Fuse.
I like the animation API, but people are gonna start talking about the jank... just takes one or two reddit posts to push to the top of google. Its one of the few things they have on {N}
Hey folks,
Indeed this is the result in almost any UI framework if you perform intensive operations in the main thread where usually the UI is operating. If you want to avoid this, such intensive operations should be performed in some other thread. The UI animation or anything else that is touching the UI cannot be offloaded to different thread.
At the moment in NativeScript there is no general purpose threading support in JavaScript however you can create threads in native code (ObjectiveC or Java) similar to our push plugin: https://github.com/NativeScript/push-plugin/tree/master/native-src/android/src/com/telerik/pushplugin
If your application needs to call SQLite, download or upload content, etc. better write the code in native as plugin and access it from JavaScript. In most cases such plugin most probably is already available.
@enchev, I thought about this same idea a while ago, maybe if there is some kind of tooling or documentation (like in react how to build native bridge) it will be helpful
What I thought is exactly telerik push plugin too that has native code inside
I haven't investigated it further but what is the tooling needed and the workflow hint for it ? It will be base for advance NS development towards speed improvements. It will be much better than other solutions if it can be easy maybe tns 1.8 will include this ? :)
@enchev - Don't get me wrong -- I love NS and I don't disagree with NS's design (well besides the lack of Threads). :grinning:
However one correction to your statement, because you accidentally left out some critical information in the way you wrote your statement. None of the other modern cross platform systems (i.e. ReactNative, Titanium and Fuse) run the gui on the JS thread. So you do not see this issue on those frameworks because all your JS code is running on a totally separate thread. So when Fuse or RN is animating something; they will smoothly animate that object the entire time no matter HOW busy your own JS code thread is. To my knowledge none of the modern frameworks use the gui thread as the main thread, so your statement is unfortunately very misleading in that it makes the reader think all frameworks have this issue, when in all reality only NativeScript has this issue by default(*).
Now on the flip side because NativeScript is the only modern framework where Gui=Main; it has the ability to very very easily access things that the other frameworks can't. (Which is what makes it an Awesome framework) It is a trade-off, and one I fully support; but until JS threads are actually supported in NS I personally feel this is the issue that will be the only black eye that NS currently has vs everyone else.
(*) - There are some exceptions to this rule in RN & Titanium, but we are talking the general case -- where this is not a issue for either of them.
@NathanaelA
Can you provide more info about your scenario? I am interested in the high-level details, e.g. animation on one thread and XYZ (what?) on another one.
Anyone else, please feel free to add your/other scenarios as well. Thanks in advance.
Hey @NathanaelA,
I'm just trying to help you and other NativeScript devs with more info about how you can create threads in NativeScript. I'm posting the link to our plugin once again just in case it is lost in the thread:
https://github.com/NativeScript/push-plugin/tree/master/native-src/android/src/com/telerik/pushplugin
@slavchev what I needed in my application was start ActivityIndicator
, then download a large binary file, save it to the device and at the end stop the ActivityIndicator
. Currently the user sees the application as unresponsive as there is no loading indication whatsoever so there is no way they know that something is being downloaded in the background.
@NathanaelA Native Android animations are performed on the UI thread and the {N} team may not control this. On iOS the animations are natively performed on another thread. As far as I understand your major point is not related with animations themselves but the fact that we run JS in the UI thread.
Well, there is one very strong reason for this - the direct API access feature of {N} (the one that you love) would be impractical because of the context switching penalty. Since you mention React Native - do a simple test with their framework where you call to native from JavaScript extensively. In such scenarios we are in orders of magnitude faster. While talking about RN - have you read this article? In fact their Animation APIs are quite slow, again hit by their expensive marshaling cost.
There will always be trade-offs and pros and cons of each approach. If you want fast access to native APIs then you stay on the UI thread. If this is not a requirement then you run JavaScript on a separate thread and communicate with native by thread locking and signaling, sending data through JSON files.
The general rule of thumb is that the UI thread should not do any time-consuming operation that is not directly related to the UI. Every such lengthy operation should be off-loaded to a background thread. The currently suggested way for doing this in {N} is by utilizing the native approach of each underlying platform using native code and then consuming the native code as a plugin from {N}.
I'm not trying to be offensive, but it's a bit odd that this issue is
still open for nearly/over a year and use cases are still being solicited.
Google strongly encourages you to run actions off of the main UI thread,
up to and including providing runOnUIThread()
to make it generally
easier to move expensive code onto separate threads and safely update
the UI. StrictMode complains loudly if any code on the UI thread blocks
for too long. If Google recommends this and if apps are sluggish and
unresponsive when those recommendations aren't followed, then shouldn't
that be the end of the story, full stop? I'm a blind Android user and
can easily pick out third-party apps that violate Google's
recommendations, because when I touch the screen to explore its
contents, they lag and crash because the UI thread is blocked from
dispatching AccessibilityEvent
objects to TalkBack. There's another
use case for providing multiple threads, but all this is doing is
supporting Google's own assertion that you shouldn't do this.
Again, not trying to be offensive, and NativeScript looks like an
interesting platform. But by default it encourages creating apps that
will go unresponsive in many common scenarios, at least on Android, if
any heavy processing is needed. If there are no plans to fix this then
it might be good to close it and tell folks to just implement heavy
processing in native code, but asking for use cases from people just
trying to follow platform recommendations doesn't make a lot of sense to me.
Got it, so I wonder if it would make sense to close this issue with that
explanation? I keep reading this thread expecting some amazing solution
that would let me spin off JS code in a background thread/worker while
not slowing down the UI. If that isn't going to happen then that's an
acceptable answer. Unfortunately a lot of the apps I develop do a fair
amount of background processing, and if I can't do those entirely in
NativeScript then that's a good thing to know. :)
Thanks.
@atanasovg I partially agree with you. But i think if we go to force users write native code, there must be a better solution than using XCode/Android studio and making separate projects. May be have a native
folder in the app structure with subfolders for android and ios where we can include native files that will be compiled on build? Otherwise for something simple (the situation I gave example above) would turn in so much overhead to manage 3 separate projects.
@ndarilek
Thanks for your feedback. I don't find your comment offensive and I don't think any of the team find it either. I like your approach and I appreciate it.
Now, let's go back to the issue. Currently, we don't know how to provide a good threading model in {N}. And I want to emphasize on "good". All we know is that we won't make it right from the first try. Our team discussed internally this issue for a long time and indeed it is hard one. One of my main reasons to ask for use cases is that I have some concrete ideas how this feature can be implemented. I cannot get any meaningful information from other implementations because there no implementations. My main concerns is how modules and plugins have to work.
For example, what are your expectations when you require("application")
on a non-UI thread (new JavaScript context)? What are your expectations when you use a single native object, say File, in two different threads (two different js objects that point to one shared native object)? Do you expect some presence of threading synchronization mechanisms? If that is the case, which ones? Do you want require("module")
to be initialized on every thread/context? If you are a plugin author how are you going to explain to the developers how they should use your module/plugin? What about the native object ownership? Do you want a native object created on one thread/context to be accessible on another one? What model do you prefer?
These are only part of the questions our team has discussed. So far, it seems much easier to stick with some event-driven approach, similar to Node.js, which perfect for I/O scenarios and not so suitable for parallel computations. We know we are going to make some trade-offs and asking for your scenarios we collect data so we can present you some initial approach/implementation which we will then start to discuss with you guys.
Got it. I think this list of questions is more helpful because, as a
potential developer, I can think about them more precisely and give more
helpful answers. More specifically:
bridge.emit("locationChanged", {latitude, longitude,
heading})
and the UI could do bridge.on("locationChanged", (err,
location) => updateMapDisplay(location))
and that would be hugely helpful.Having said all that, I'm not necessarily advocating this as the way to
go forward, and it may not work for others. But in thinking of the kinds
of problems I'd like to solve with NativeScript, React Native or
whatever non-native runtime I want on my phone, and in terms of the
issues you've raised, having a separate JS context for background tasks
and passing a limited subset of messages across thread bounds would
probably get me a long way to where I want to be.
I hope that helps. Thanks for putting it in terms of questions/specific
issues.
For example, what are your expectations when you require("application") on a non-UI thread (new JavaScript context)? What are your expectations when you use a single native object, say File, in two different threads (two different js objects that point to one shared native object)? Do you expect some presence of threading synchronization mechanisms? If that is the case, which ones? Do you want require("module") to be initialized on every thread/context? If you are a plugin author how are you going to explain to the developers how they should use your module/plugin? What about the native object ownership? Do you want a native object created on one thread/context to be accessible on another one? What model do you prefer?
@slavchev I think even allowing simplified threads with having access to only native classes will be a big :+1: for {N}.
I think even with having these limitations will handle most (if not all) the situations above
@atanasovg - Oh, I realize the reason everything works the way it does -- trust me I've dug into the runtimes on both platforms and the core modules too, I have a pretty good grasp of the entire eco-system. :grinning: I was trying to emphasis because you DON'T let us put anything onto a background JS thread, which forces us to run things in the main thread the UI is adversely affected, and this is what you see when you do any type of busy work. Visualizing it really brings the point home. This effects the entire UI, not just animations. And since we are just shy of a year since I first opened this issue; I wanted to make sure this issue still is considered important to us in the community!
As for RN, their animation CAN be slow if you are busy in your JS thread; however they have the convenient requestAnimationFrame built is so that you can fire your updates between frames so that it doesn't slow down your animation. (Assuming your work is in small enough chunks, otherwise you will get some of the same jank we see in NS). However, they actually have been working on moving the Animation system onto the ui thread and the _first_ patch was just released for review and looks like based on the pull request only a few minor things hanging it and it should show up in the next version of React. So, once this in play; RN should always have smooth jank free animations even when the JS thread is busy... In addition even with Janky animations in the current RN, the interface itself doesn't freeze; I can type fine in a textbox without any issues when the JS thread is busy. In NS; this is very painful and the WHOLE interface freezes not just animations.
@slavchev - I assume you saw the three images I uploaded to the thread earlier; Image 2 & 3 is the issues I have. The screen UI (not just animations) is literally locked/frozen until you can break out of processing to give the main thread a couple 10ms to do something. In one of my apps, at startup I have a section of work where I parse a multi-megabyte file and then update a database with the information. I currently actually have to write code like so:
IF I had access to a background JS thread I would do:
Now as to the expectations of a Background thread: I honestly think the WebWorker modal is fairly correct; the thread should be _totally_ independent of the parent -- it has NO access to the UI nor ANYTHING running in _any_ other thread including the main thread. But it does have access to the native platform API's. If you attempted to do a require('application') it would currently throw an error because Application attempts to setup things on the UI thread that wouldn't be valid. So my assumption would be at the top of the Application.js you would add something like:
if (global.isThread) return; Or some sort of short-circuit to eliminate UI modules from actually attempting to run on a processing only thread.
The only communication should be:
var x = new WebWorker("worker.js");
x.on('message',function(blah) {
if (blah === 1) x.terminate();
});
x.postMessage(JSON.stringify(someData));
worker.js
var fs = require('file-system');
this.postMessage('Hey I'm running!');
this.on('message', function (obj) {
var coolData = JSON.parse(obj);
....
// do lots of work.
// use FS to read/write data
});
In a nutshell:
@NathanaelA So, to rephrase what you are saying - because {N} does not allow you to run JS on another thread you execute CPU intensive code on the main thread, which freezes the UI. Well, every GUI platform strongly advises against running blocking code on the main UI thread. Btw, would you share what kind of work you are actually performing in your screenshots? I'd love to check whether this is a common application scenario.
Now, let's accept for a moment that background JS processing is a currently not available feature in {N}. And the {N} team may not engage with any particular time frame for implementing it. What are our options then to perform CPU-intensive logic?
Obviously, we'll want to go for the second one. Imagine we have asynchronous plugins for most of the common use cases - like the HTTP cross-platform module or the push notifications plugin. If this is true then the pure application developer would be good to go by just installing the needed plugins. With that said - @NathanaelA, @PeterStaev and every plugin author, we need your help, guys, to isolate these common scenarios and to create plugins to cover them.
I know going native is probably not the most effective approach for plugin authors but it is currently the only available (and viable) one. And I can only assure you that we will definitely have your feedback in mind when prioritizing our backlog.
Btw, @NathanaelA, what about your workaround with utilizing a WebView and using its workers support?
@atanasovg - That is a very interesting way to rephrase my words, but in a nutshell yes. I am well aware of the issues with running everything on the main/gui thread; why do you think I opened this issue almost a year ago, and I keep pinging you guys about it? I foresaw the issue for several types of workloads almost immediately after I started using NS.
Even though I will describe my workflow; this is still a very generic issue; anything that causes any type of processing will mess up the screen as the screen will not respond including input boxes.
Screen gifs, are pure stupid JS work to illustrate the issue. However in one of my real apps; the animation was Frame 1, then final frame, NOTHING in between. Once I broke the work bits down into a ton of smaller chunks and used setTimeouts (Hacky!) to move to the next piece of work , the animation is not as smooth as Screen 2 and can randomly be very janky (depending on what it is updating). So I have removed the animation from the screen while it is processing. Once processing is finished, animation is enabled (since it is a login screen also and the user might let it sit for a while).
My application as I explained in simpler terms to @slavchev downloads (background) a list of products and price updates; on initial startup. Unfortunately since items go in and out of stock and packages change by the minute; this list is huge on startup (I am working with the customer to attempt to make this a lot smaller by allowing paging and (BTW: NativeScript doesn't support GZIP yet; so the actual raw TEXT download takes about twice as long as needed, so it is also a speed hit) Then I process the individual pieces of the update and update multiple database tables. Once that is done the user can then can navigate and view/order things, etc and that part is very standard.
The issues are:
Even if the service moves to a paged data set; each dataset downloaded will still have to be processed and will cause an interface hiccup since the processing is still cpu heavy on the main thread, however the user might attribute that to the download speed since this would be done dynamically as they scroll.
On my WebWorkers plugin, I had such high hopes for it helping with this; but without being able to talk to SQLite from the WebWorker the amount of data marshaling cost about the same amount of time as processing it all on the main thread. ;-(
Potential Solutions:
Love the discussions :)
What I'd like to do is using the native code to do the background processing ex: asynctask in android, and like @enchev said it can be done like the tns notification plugin, my problem is, this process is not very developer friendly, so somehow there's an easy way (maybe like the recent activity android that can be enhanced)
But then again, I dont know very much :)
@atanasovg it is not a good practice to extract everything to a plugin. For example the workflow that @NathanaelA gave above. This is a specific use case for his app. I dont see any benefit in extracting this as a plugin for the masses. Not to mention that i might have some proprietary logic which i do not want to expose as a plugin for apparent reasons ;)
like @x4080 says above - it is not very developer friendly to make every portion of a more resource intensive task in native development environment (android studio or XCode). If I have to open XCode for 50% of the code I have what benefit i have in using {N} instead of just going pure native?
@PeterStaev I bet having the SQLite plugin do its work on a background thread would most probably solve @NathanaelA's issues. No need to extract the application logic to another thread. I still believe that there exists a set of plugins that would solve, say 90%, of the application scenarios. And instead of arguing whether this is true or false let's try to compile this list of plugins and discuss case by case.
So far I've heard a scenario related to SQLite data manipulation - well, it is obvious that this is a general purpose plugin that does not have appropriate code and is the ideal candidate for offloading its work to another thread.
@PeterStaev 'n all, please fill the following list with scenarios where you'd need a background thread:
@atanasovg i already listed my case above but here it is again:
Personally I would just like a way to "process" something off somewhere else and _whatever_ is handing that be a core part of {N} so I know it's fully tested and rock-solid. I'd be less optimistic about this being done generically by a plugin author who might disappear in 2 months.
Yes and plugins is too big for small services that needs async like async .. Task :)
BTW, since Angular2 is a huge push right now by the NS team; are you aware of: https://github.com/angular/angular/blob/master/modules/angular2/docs/web_workers/web_workers.md :grinning: You can add it to the A2 story, and then I'll even be happy about all the time on a2 support. :grinning:
One scenario for me would be doing data transformations, i.e. iterating on datasets fetched from my backend. A workaround is to do the transformations server-side, but it seems a bit counter intuitive, as the transformations will often be specific to a given view.
A concrete example where background processing made a huge difference in my native code: I am displaying a map, and fetching points of interests inside the area currently displayed. After the POIs are fetched, I need to calculate the display location for each of them, and group them if they are too close to each other. Doing this on the UI thread, will make the map unresponsive and sluggish.
@prebenl I love your thinking outside the box. If I had the ability to do anything on the server, I would be doing something to make the dataset a lot (lot) smaller., but I have no control over the server side. Everything has to be done in the app...
+1
I hope it will be possible to send the reference and not the object between the threads. (for performance)
Any plans for blog to develop native plugin for background threading using Android studio and xcode ? Or maybe NS guys can describe how they develop the tns plugin? It will be great time saving
Thanks
Hey everyone - In order to explain better the current state of the threading model we wrote a blog post. It also outlines what we are planning for the future and how you can use background threads now.
http://developer.telerik.com/featured/benefits-single-threading-model-nativescript/
nice blog, so the next JavaScript background thread will be able to pass variable from the main JavaScript? and in iOS will it use wkwebview for more performance?
+1
I'm closing this issue, lets use the other ones for the current state -
https://github.com/NativeScript/ios-runtime/issues/620
https://github.com/NativeScript/android-runtime/issues/532
We would love to continue the discussion there on the current thinking!
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Any plans for blog to develop native plugin for background threading using Android studio and xcode ? Or maybe NS guys can describe how they develop the tns plugin? It will be great time saving
Thanks