ES7 introduces async functions, which allow you to write asynchronous code with a synchronous syntax. Unfortunately this doesn't work well with AngularJS: awaited code will run outside of Angular's digest loop, and therefore it won't trigger watchers or view updates.
The problem
ES7 introduces async functions that allow to write async code with a synchronous syntax. This looks like this:
This works because await
expects a promise as arguments, and it waits until the promise is resolved before continuing.
Unfortunately this doesn’t work well in AngularJS: awaited code is not run in the digest loop, and therefore we need to put $scope.$apply
calls all over the place. This results in code like this:
Obviously this isn’t ideal, it would be better if we could omit the $scope.$apply
calls.
Meet $async
Fortunately there is a way out. Thanks to the generator functions introduced in ES6 we can write our own async engine that does work well with AngularJS. At Magnet.me we’ve created the $async module which does exactly that. With $async
we can rewrite the initialize function like this:
Instead of an async function we now use a generator function passed to $async
, and instead of await
ing a promise we now yield
a promise.
How it works
Generator functions do not run to completion when they are invoked. Instead they return an iterator that can be iterated over manually. This iterator will stop and “return” at every call to yield
. For example, the following generator function generates all positive integers:
The $async
module makes use of the ability to pause generator functions to emulate async functions. It expects a generator that will generate promises, and it will chain all these promises together correctly. The result is that each yield
call will wait for its promise to be resolved before continuing. The core of $async
looks something like this:
Now that we have our own async engine it is trivial to make it work properly with Angular: we can add the call to $scope.$apply
in the iterateAsync
function and there it is: an async function that works with AngularJS!
The entire module is only a couple of lines long, if you’re interested in all the details then check it out here!
Inspiration
To give credit where credit’s due, the idea of using generators to implement aysnc functions isn’t new. Libraries that do so exist for a long time, with the most well-known being co. $async
is mostly inspired by co
, but more lightweight and Angular-flavored.