Slow performance in hybrid AngularJS and Angular application in Safari - angularjs

I have started recently the migration of an AngularJS application to Angular 4 using the upgrade module.
One of my AngularJS directives uses a third party library (ngFlow) to upload files using XMLHttpRequest.send(). When running in hybrid mode, uploads work fine both, in Chrome and in Firefox. However, in Safari the app becomes very slow during an upload and the browser process reaches 100% CPU used.
Using Safari web tools, I see that there is a lot of calls to globalZoneAwareCallback from zone.js.
My impression is that the Angular zone is kicking off change detection for every XMLHttpRequest progress event happening during the upload.
I am aware that I could use runOutsideAngular from NgZone to avoid this, but I don't know how to use it in the case where the async call is happening in a third party AngularJS library or if there is any other solution to address this issue.

Finally I managed to resolve the issue using runOutsideAngular.
First, I downgraded the NgZone module to use it in my AngularJS code:
factory('ngZone', downgradeInjectable(NgZone));
And then I injected the service in the upload directive and use it to run the file uploads out of the Angular zone:
ngZone.runOutsideAngular(() => $flow.upload());

To avoid all issues with $digest and performance I recommend using downgradeModule - it bootstraps AngularJS outside of the Angular zone and keeps the two change detection systems separate.

Related

Are there any alternatives to ngUpgrade for running angular and angularjs side-by-side, or a way to opt out of ngUpgrade's $digest triggers?

I have a rather large angular.js 1.6 app that I would like to migrate to Angular, but using ngUpgrade causes way too many $digests to be triggered (i.e. every time Zone.onMicrotaskEmpty is fired). Unfortunately the app I am migrating is already not too great performance-wise, so every extra $digest is a pretty big deal. While I can mitigate this somewhat with ngZone.runOutsideAngular(), what I would really like is to totally disable the automatic triggering of $digests from the upgrade module, and just manually trigger them when necessary; since the app is composed of coarse-grained components which I will migrate one-by-one, there will be little need for a change in Angular to trigger a $digest in angular.js.
Here are a few of the possible solutions I am considering; are any of them more "standard" (or less risky / error prone) than the others?
Use a locally modified version of ngUpgrade with the call to rootScope.$digest() removed
Host upgraded Angular components in an iframe and use postMessage() for interaction with the app
Host upgraded Angular components in a web component (have not yet investigated how communication would work in that case)
Bootstrap both an angular.js and an Angular app from the same document, letting them both process their own directives/components on the page
Update (8/23): For now I am giving option 1 a try (locally modifying the upgrade js file); while I usually like to avoid doing such things, it seems like the safest bet so far.
There are two ways to bootstrap a Hybrid App:
UpgradeModule - bootstraps both the AngularJS (v1) and Angular (v6) frameworks in the Angular zone
DowngradeModule - bootstraps AngularJS outside of the Angular zone and keeps the two change detection systems separate.
I have tried both ways. To avoid all issues with $digest and performance I recommend using DowngradeModule

Upgrading AngularJS app to an hybrid Angular-1.6 / Angular-4 kills the perf

I've just updated my AngularJS 1.6 app by following the Angular 4 upgrade guide. Basically I've added new angular 4 dependencies in package.json, bootstrapped the app via UpgradeModule and created a new simple component in angular 4. Everything works as expected but the performance is really bad!
The application is a dashboard application with potentially lots of widget components and lots of http requests to the backend to fill each widget content.
Depending on the dashboard, the upgraded app is 2x to 5x slower to load and display the dashboard, and chrome network console shows the http requests are run in a sequence instead of being shot all at once like in the 1.6 version. Overall, the UI is also a lot less fluid.
I've played with ngZone and tried to run requests outside of angular zone.runOutsideAngular(() => { ... }) to reduce refresh cost due to change detection. The result is slightly faster but still far slower than the original 1.6 only version.
Is there something to consider when upgrading to an hybrid 1.6-4 app to keep great original performance? Thanks!
We are using hybrid application. According to our measures NG2 adds about 20% to the initial NG1 time. It not so bad, but we did a lot of staff after just configuring hybrid:
1) - Bundles instead of multiply requests for NG2 (thanks CLI)
2) - AOT for prod; JIT for dev
3) - Tree-shaking
4) - Conditional poly-fills (modern browsers don't require any poly-fills, but they are necessary for old browsers)
We are trying to integrate the following staff as well:
1) - Lazy loading. But I am not sure if it is working for hybrid applications
2) - Web Worker to move NG2 to a separate thread. But again I am still not sure if it is working for hybrid applications
3) - Some custom detect changes strategies
Here is a good checklist regarding NG2 performance. I hope it will help you.
I have hybrid app Ng1.5+Ng2.4.0. I also had performance problems with angular4 in hybrid mode by 2 reasons.
This relates to DEBUG only since ng4 performs extra checks. In production mode (call enableProdMode() before bootstrap to turn it on) angular4 even a bit faster than ng2.
import { enableProdMode } from '#angular/core';
enableProdMode ();
Ng4 in hybrid mode schedules digest if any watch expression function in angularjs made async call. I.e. if you use lodash throttle function in angularjs watch expression to reduce digest rate then having Ng4 can lead to opposite effect -- digests will queue as snowball.

Protractor browser.driver.getCurrentUrl vs browser.getCurrentUrl

I'm running an Angular app and I'm trying to get the current URL when testing on protractor. Which one to use?
browser.driver.getCurrentUrl() or browser.getCurrentUrl() ?
If this is an Angular application under test - use browser, otherwise - browser.driver.
To quote #jmr from a relevant github issue:
If you need to interact with a non-Angular page, you may access the wrapped webdriver instance directly with browser.driver.
Though, note that both are gonna work if this is Angular application under test. Some people even said that found browser.driver more reliable if it the sync time is longer than usual:
Just to add to this - I find that browser.driver works better on AngularJS apps that take time to sync. I have tried both and for some reason browser.driver is more reliable.
Though, I've personally used browser.getCurrentUrl() and cannot recall any problems.

Fast way to develop AngularJS in a Java environment

I am currently working on a Java based Maven project that has a REST backend module and using angular JS as a frontend that uses the backend for data. The 2 modules are named "rest" and "web" accordingly and are deployed as 2 separate war files to a glassfish instance during development. The glassfish is on a different machine.
My problem is that this is kind of slow, especially when developing the angular based frontend. Fix a minor spelling mistake, package, redeploy. Not that slow but every character change or fiddling with angular is another 20-30 seconds lost.
One thing I tried is to directly load the files from the source directory into the browser with file:// tag. This is OK as long as it tries to call the REST backend which fails due to CORS (I don't remember the exact error message, it just doesn't work). This happens a lot so it's a no-go.
I'm open to every kind of solution to develop angular in a way that I could see my changes instantly instead of deploying it every time? Much like the guy does in the egghead videos.
I would recommend breaking your Angular JS application into its own separate project, this would be a new HTML5 project on Netbeans. That way you can focus on pure backend and frontend development in their respective projects and you do not have to manually separate the war files. This link will help you to get CORS working if you are defining your RESTFUL services with Jersey Access-Control-Allow-Origin in ajax call to jersey rest web services. Or you can just mock the data out in the front end project.

Can I use AngularJS 'ng-view' in TideSDK 1.3.1beta?

I've got a simple TideSDK application going, using AngularJS. Works nicely.
Recently as I started adding features, I replaced my single ng-include with ng-view and Angular routing. It works great in Chrome, but errors galore in TideSDK.
Is it possible to use ng-view in an application built with TideSDK 1.3.1beta?
This is due to the age of the embedded webkit within TideSDK. TideKit is on its way to release quite soon and includes latest webkit for much greater HTML5 compliance. You will be able to migrate your existing code once it is available.

Resources