No description, website, or topics provided.
Switch branches/tags
Clone or download
Latest commit d0e7a50 Feb 22, 2017
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src Added method to wrap entire services with $async May 13, 2016
test Added method to wrap entire services with $async May 13, 2016
.babelrc Added tests Nov 10, 2015
.gitignore Initial implementation Nov 9, 2015
.travis.yml Added tests Nov 10, 2015
README.md Update README.md Feb 22, 2017
package.json 1.1.0 May 13, 2016

README.md

Build Status

Magnet.me Logo

$async

$async is an async/await implementation based on generators for use with angular.

Install

npm install ng-async

Usage

As service

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;
		});
	});

To wrap a service/controller

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.

Prerequisites

  • 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

Why?

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 awaited 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.

How should I use it?

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");
});

How can I pass arguments to an $async function and what happens with this?

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