Promises with AngularJS
This fiddle illustrates how we can use the native Promise with AngularJS. The Promise knows how to trigger only the minimum required number of digest cycles.
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div ng-app="app">
<div ng-controller="MainCtrl as $ctrl">
<p>asyncValue: <strong>{{ $ctrl.asyncValue }}</strong></p>
<p>classicPromiseResolve: <strong>{{ $ctrl.classicPromiseResolve }}</strong></p>
<p>promisesRace: <strong>{{ $ctrl.promisesRace }}</strong></p>
</div>
</div>
</body>
</html>
JavaScript
angular
.module('app', [])
// At run time, we overwrite the native Promise using Proxy
// IDEA FOR IMPROVEMENT: using angular.injector(['ng']).get('$rootScope') we can get the $rootScope even before AngularJS has bootstraped.
.run(function($rootScope) {
function triggerDigestIfNeeded() {
// $applyAsync acts as a debounced funciton which is exactly what we need in this case to get the minimum of digest cycles fired.
$rootScope.$applyAsync();
};
// This principle can be used with other native JS "features" when we want to integrate then with AngularJS; for example, fetch.
Promise = new Proxy(Promise, {
// We are interested only in the constructor function
construct(target, argumentsList) {
return (() => {
const promise = new target(...argumentsList);
// The first thing a promise does when it gets resolved or rejected, is to trigger a digest cycle, if needed
promise.then((value) => {
triggerDigestIfNeeded();
return value;
}, (reason) => {
triggerDigestIfNeeded();
return reason;
});
return promise;
})();
}
});
})
// This outputs the number of digest cycles
.run((() => {
let digestCycles = 0;
return function($rootScope) {
$rootScope.$watch(() => console.log(++digestCycles))
}
})())
// Here we are testing the Promise and async/await features
.controller('MainCtrl', function() {
this.asyncValue = 'unresolved';
this.classicPromiseResolve = 'unresolved';
this.promisesRace = 'unresolved';
this.$onInit = () => {
this.testAsyncFunction();
this.testClassicPromiseResolve();
this.testPromisesRace();
};
this.testClassicPromiseResolve = () => {
...