$async is an async/await implementation based on generators for use with angular.
npm install ng-async
import ngAsync from 'ng-async';
angular.module('my-module', [ngAsync.name])
.controller('my-controller', function($async) {
const init = $async(function*() {
const { data : users } = yield $http.get('/users');
$scope.users = users;
});
});
import ngAsync, { $async } from 'ng-async';
angular.module('my-module', [ngAsync.name])
.controller('my-controller', $async(function*($http) {
'ngInject';
const { data : users } = yield $http.get('/users');
$scope.users = users;
}));
Note: To wrap a service/controller it must be explicitly annotated. The example uses ng-annotate to do it for us.
Note: keep in mind that an $async
function returns a promise, not a value. This is especially important with factories, since their return value will be used for injection.
- ES6 support in either your host environment or your build chain. At minimum your environment should support the following:
- Generators
- Modules
- Lambdas
const
/let
- Rest parameters
- Angular should be available to the module via the module loader with
import 'angular'
. - Angular
^1.3.0
ES7 introduces async functions, which create a way to write asynchronous code with a synchronous syntax.
Unfortunately this doesn't work well with Angular: code after a call to await
does not run in the digest cycle, and thus it won't update the screen. To illustrate:
<ul>
<li ng-repeat="user in users">
{{ user.name }}
</li>
</ul>
$scope.users = [];
async function init() {
const { data : users } = await $http.get('/users');
//This does not run in a digest cycle
$scope.users = users;
}
Since the $scope.users = users;
line does not run in a digest cycle, the view isn't updated. To solve this with async functions you need to put $scope.$apply
calls after each await
ed statement.
$async
implements similar functionality with the help of generators in such a way that all code in an $async
function does run in the digest cycle.
Usage of $async
is very similar to usage of plain async functions. Instead of creating an async function you should pass a generator function to $async
, and where you would use await
in an async function you now need to use yield
. Additionally you don't need the $scope.$apply
calls anymore.
//with async functions
async function foo() {
$scope.someStuff = await getSomeStuffAsync();
$scope.$apply();
$scope.someOtherStuff = await getSomeOtherStuffAsync();
$scope.$apply();
console.log("we're done");
}
//equivalent with $async, but angular proof:
const foo = $async(function*() {
$scope.someStuff = yield getSomeStuffAsync();
$scope.someOtherStuff = yield getSomeOtherStuffAsync();
console.log("we're done");
});
Arguments are directly passed to the generator function and the this that is used to call the $async
function will also be used for the generator function. Example:
const myObj = {
bar : $async(function*(a, b) {
console.log(`a: ${a}`);
console.log(`b: ${b}`);
console.log(`this === myObj: ${this === myObj}`);
});
}
myObj.bar(1, 2);
//Outputs:
//a: 1
//b: 2
//this === myObj: true