UNPKG

28.5 kBMarkdownView Raw
1# UPDATE June 2018
2
3Do you need this library?
4
5This library has enabled async/await coding style in Node.js since 2014. But JavaScript now has native async/await.
6JS async/await was standardized as part of ES2017, and has been enabled by default in Node.js since v7.6.
7
8So, do you still need this library? If you are just starting to use async/await, the answer is probably no. Use native
9async/await. If you're maintaining a codebase that uses this library, or that needs to run on a old version of Node.js,
10then you may want to keep using it, but consider migrating to native async/await eventually. If you need deep coroutines
11for an advanced scenario, there may still be a case for using this library, since native async/await only supports
12shallow coroutine semantics.
13
14# Guide to `asyncawait` v1.0
151. [Introduction](#1-introduction)
162. [Feature/Gotcha Summary](#2-featuregotcha-summary)
173. [How Does it Work?](#3-how-does-it-work)
184. [Compared to...](#4-compared-to)
195. [Performance](#5-performance)
206. [Quick Start](#6-quick-start)
21 - [Installation](#installation)
22 - [Async/Await 101](#asyncawait-101)
23 - [Basic Example](#basic-example)
24 - [More Examples](#more-examples)
257. [`async` in Depth: Suspendable Functions](#7-async-in-depth-suspendable-functions)
26 - [Accepting Arguments and Returning Values](#accepting-arguments-and-returning-values)
27 - [Handling Errors and Exceptions](#handling-errors-and-exceptions)
28 - [Obtaining Results from Suspendable Functions](#obtaining-results-from-suspendable-functions)
29 - [Preservation of `this` Context](#preservation-of-this-context)
30 - [Creating and Using Asynchronous Iterators](#creating-and-using-asynchronous-iterators)
31 - [Eager versus Lazy Execution](#eager-versus-lazy-execution)
32 - [Nesting, Composition and Recursion](#nesting-composition-and-recursion)
33 - [The `async.mod` Function](#the-asyncmod-function)
348. [`await` in Depth: Awaitable Expressions](#8-await-in-depth-awaitable-expressions)
35 - [What Works with `await`?](#what-works-with-await)
36 - [Obtaining Awaitable Versions of Node-Style APIs](#obtaining-awaitable-versions-of-node-style-apis)
37 - [Maximising Concurrency](#maximising-concurrency)
38 - [Variations of `await`](#variations-of-await)
399. [Recipes](#9-recipes)
40 - [Handling HTTP Routes with Express](#handling-http-routes-with-express)
41 - [Asynchronous Testing with Mocha](#asynchronous-testing-with-mocha)
4210. [API Reference](#10-api-reference)
4311. [Acknowledgements](#11-acknowledgements)
4412. [License](#12-license)
45
46
47
48# 1. Introduction
49`asyncawait` addresses the problem of [callback hell](http://callbackhell.com/) in Node.js JavaScript code. Inspired by [C#'s async/await](http://msdn.microsoft.com/en-us/library/hh191443.aspx) feature, `asyncawait` enables you to write functions that **appear** to block at each asynchronous operation, waiting for the results before continuing with the following statement. For example, you can write the following in plain JavaScript:
50
51```javascript
52var foo = async (function() {
53 var resultA = await (firstAsyncCall());
54 var resultB = await (secondAsyncCallUsing(resultA));
55 var resultC = await (thirdAsyncCallUsing(resultB));
56 return doSomethingWith(resultC);
57});
58```
59
60which, with one [proviso](#obtaining-awaitable-versions-of-node-style-apis), is semantically equivalent to:
61
62```javascript
63function foo2(callback) {
64 firstAsyncCall(function (err, resultA) {
65 if (err) { callback(err); return; }
66 secondAsyncCallUsing(resultA, function (err, resultB) {
67 if (err) { callback(err); return; }
68 thirdAsyncCallUsing(resultB, function (err, resultC) {
69 if (err) {
70 callback(err);
71 } else {
72 callback(null, doSomethingWith(resultC));
73 }
74 });
75
76 });
77 });
78}
79```
80
81The function `foo` does not block Node's event loop, despite its synchronous appearance. Execution within `foo` is suspended during each of its three asynchronous operations, but Node's event loop can execute other code whilst those operations are pending. You can write code like the above example in a HTTP request handler, and achieve high throughput with many simultaneous connections, just like with callback-based asynchronous handlers.
82
83In short, `asyncawait` marries the high concurrency of asynchronous code with the visual clarity and conciseness of synchronous code. Rather than passing callbacks and error-backs, you can `return` values and use `try/catch` blocks. Rather than `require`ing specialised asynchronous control-flow constructs like [`each`](https://github.com/caolan/async#eacharr-iterator-callback) and [`whilst`](https://github.com/caolan/async#whilsttest-fn-callback), you can use plain JavaScript constructs like `for` and `while` loops.
84
85
86
87# 2. Feature/Gotcha Summary
88* Eliminates callback spaghetti code.
89* Enables the use of ordinary JavaScript control flow constructs for asynchronous operations.
90* Syntax is plain JavaScript, and behaves much like C#'s async/await.
91* Seamless interoperation with most other libraries, including [Express](expressjs.com), [Mocha](http://mochajs.org/), [Underscore](http://documentcloud.github.io/underscore/), [Bluebird](https://github.com/petkaantonov/bluebird), etc.
92* [Fast](./comparison) and lightweight.
93* Completely [non-blocking](http://stackoverflow.com/a/14797359).
94* Does not require [ES6 generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*).
95* No code preprocessing or special build steps, simply write and execute your code normally.
96* Built with [node-fibers](https://github.com/laverdet/node-fibers).
97* [TypeScript](http://www.typescriptlang.org/) and X-to-JavaScript friendly (since ES6 generators are not required).
98* TypeScript typings are embedded.
99* Works only in Node.js, not in browsers (since it uses node-fibers).
100
101
102
103# 3. How does it work?
104Like [`co`](https://github.com/visionmedia/co), `asyncawait` can suspend a running function without blocking Node's event loop. Both libraries are built on [coroutines](http://en.wikipedia.org/wiki/Coroutine), but use different technologies. `co` uses [ES6 generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*), which work in Node >= v0.11.2 (with the `--harmony` flag), and will hopefully be supported someday by all popular JavaScript environments and toolchains.
105
106`asyncawait` uses [`node-fibers`](https://github.com/laverdet/node-fibers). It works with plain ES3/ES5 JavaScript, which is great if your tools do not yet support ES6 generators. This may be an important consideration when using [compile-to-JavaScript languages](https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS), such as [TypeScript](http://www.typescriptlang.org/) or [CoffeeScript](http://coffeescript.org/).
107
108A similar outcome may be achieved by transforming JavaScript source code in a preprocessing step. [streamline.js](https://github.com/Sage/streamlinejs) is an example of this method. Code using `asyncawait` is executed normally without any code tranformation or preprocessing.
109
110
111
112# 4. Compared to...
113`asyncawait` represents one of several viable approaches to writing complex asynchronous code in Node.js, with its own particular trade-offs. Notable alternatives include [`async`](https://github.com/caolan/async), [`bluebird`](https://github.com/petkaantonov/bluebird/) and [`co`](https://github.com/visionmedia/co), each with their own trade-offs. The following table summarises some of the alternatives and their pros and cons. For more information about how the alternatives compare, take a look in the [comparison](./comparison) folder.
114
115`asyncawait` may be a good choice if (a) you need highly concurrent throughput, (b) your asynchronous code must be clear and concise, (c) your code targets Node.js, and (d) you are limited to ES3/ES5 syntax (e.g. you write in TypeScript or CoffeeScript).
116
117| | Max. throughput (full event loop utilisation) | Concise, clear code (control-flow, data-flow and error-flow) | Max. support for Node.js dev/build tools | Max. support for JS envs (eg Node + browsers)
118|---|---|---|---|---|
119| Plain synchronous code | :heavy_exclamation_mark:<sup>[1]</sup> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
120| Plain callbacks | :white_check_mark: | :heavy_exclamation_mark:<sup>[2]</sup> | :white_check_mark: | :white_check_mark: |
121| Callbacks + control-flow (e.g. [`async`](https://github.com/caolan/async)) | :white_check_mark: | :heavy_exclamation_mark:<sup>[3]</sup> | :white_check_mark: | :white_check_mark: |
122| Promises + control-flow (e.g. [`bluebird`](https://github.com/petkaantonov/bluebird/)) | :white_check_mark: | :heavy_exclamation_mark:<sup>[3]</sup> | :white_check_mark: | :white_check_mark: |
123| Coroutines with [`co`](https://github.com/visionmedia/co) | :white_check_mark: | :white_check_mark: | :heavy_exclamation_mark:<sup>[4]</sup> | :heavy_exclamation_mark:<sup>[5]</sup> |
124| Coroutines with `asyncawait` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_exclamation_mark:<sup>[6]</sup> |
125
126**Footnotes:**
127<sup>**[1]**</sup> Each synchronous call blocks Node's event loop. All concurrent tasks are blocked, and the event loop sits idle, until the call completes.
128<sup>**[2]**</sup> Plain callbacks rapidly become unwieldy for complex asynchronous tasks. See [comparison](./comparison).
129<sup>**[3]**</sup> Whilst better than plain callbacks, these styles still produce longer and more complex code than synchronous or coroutine-based code. See [comparison](./comparison).
130<sup>**[4]**</sup> Some tools do not (yet) support ES6 generators, including [compile-to-JavaScript languages](https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS) such as [TypeScript](http://www.typescriptlang.org/) and [CoffeeScript](http://coffeescript.org/).
131<sup>**[5]**</sup> [ES6](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts) still has patchy browser support.
132<sup>**[6]**</sup> Strictly limited to Node.js environments (i.e. no browsers) due to the use of [`node-fibers`](https://github.com/laverdet/node-fibers).
133
134
135
136# 5. Performance
137How well does `asyncawait` perform? The answer depends on what kinds of performance you care about. As a rough guide, compared with bare callbacks, expect your code to be 70% shorter with 66% less indents and run at 79% of the speed of bare callbacks. OK, so don't trust those numbers (which actually are [real](./comparison/README.md#comparison-summary)) but do check out the code in the [comparison](./comparison) folder, and do run your own [benchmarks](./comparison/benchmark.js).
138
139
140
141# 6. Quick Start
142
143### Installation
144`npm install asyncawait`
145
146### Async/Await 101
147`asyncawait` provides just two functions: `async()` and `await()`. You can reference these functions with the code:
148```javascript
149var async = require('asyncawait/async');
150var await = require('asyncawait/await');
151```
152Use `async` to declare a suspendable function. Inside a suspendable function, use `await` to suspend execution until an awaitable expression produces its result. Awaitable expressions typically involve performing asynchronous operations.
153
154Note the spacing after `async` and `await` in the examples. They are just plain functions, but the space makes them look more like keywords. Alternatively if you really want them to stand out, you could use names like `__await__` or `AWAIT`, or whatever works for you.
155
156### Basic Example
157```javascript
158var async = require('asyncawait/async');
159var await = require('asyncawait/await');
160var Promise = require('bluebird');
161var fs = Promise.promisifyAll(require('fs')); // adds Async() versions that return promises
162var path = require('path');
163var _ = require('lodash');
164
165/** Returns the number of files in the given directory. */
166var countFiles = async (function (dir) {
167 var files = await (fs.readdirAsync(dir));
168 var paths = _.map(files, function (file) { return path.join(dir, file); });
169 var stats = await (_.map(paths, function (path) { return fs.statAsync(path); })); // parallel!
170 return _.filter(stats, function (stat) { return stat.isFile(); }).length;
171});
172
173// Give it a spin
174countFiles(__dirname)
175 .then (function (num) { console.log('There are ' + num + ' files in ' + __dirname); })
176 .catch(function (err) { console.log('Something went wrong: ' + err); });
177```
178
179The function `countFiles` returns the number of files in a given directory. To find this number, it must perform multiple asynchronous operations (using `fs.readdir` and `fs.stat`). `countFiles` is declared as a suspendable function by wrapping its definition inside `async(...)`. When `countFiles` is called with a `dir` string, it begins executing asynchronously and immediately returns a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) of a result. Internally, `countFiles` appears to have synchronous control flow. Each `await` call suspends execution until its argument produces a result, which then becomes the return value of the `await` call.
180
181### More Examples
182The [examples](./examples) folder contains more examples. The [comparison](./comparison) folder also contains several examples, each coded in six different styles (using plain callbacks, using synchronous-only code, using the `async` library, using the `bluebird` library, using the `co` library, and using this `asyncawait` library).
183
184
185
186# 7. `async` in Depth: Suspendable Functions
187The subsections below refer to the following code:
188```javascript
189var suspendable = async (function defn(a, b) {
190 assert(...) // may throw
191 var result = await (...)
192 return result;
193});
194var suspendable2 = async.cps (function defn(a, b) {...});
195var suspendable3 = async.thunk (function defn(a, b) {...});
196var suspendable4 = async.result (function defn(a, b) {...});
197```
198
199### Accepting Arguments and Returning Values
200Suspendable functions may accept arguments. Calling `suspendable(1, 2)` will in turn call `defn(1, 2)`. Suspendable functions may be variadic. They report the same arity as their definition (i.e. `suspendable.length` and `defn.length` both return `2`).
201
202A suspendable function's definition may return with or without a value, or it may throw. Returning without a value is equivalent to returning `undefined`. The return value of the definition function becomes the result of the suspendable function (see [Obtaining Results from Suspendable Functions](#obtaining-results-from-suspendable-functions)).
203
204### Handling Errors and Exceptions
205A suspendable function's definition may throw exceptions directly or indirectly. If any of the `await` calls in `defn` asynchronously produces an error result, that error will be raised as an exception inside `defn`.
206
207Within the definition of a suspendable function, exceptions may be handled using ordinary `try/catch` blocks. Any unhandled exception thrown from within `defn` will become the error result of `suspendable`.
208
209### Obtaining Results from Suspendable Functions
210A suspendable function executes asynchronously, so it cannot generally `return` its result (or `throw` an error) directly. By default, `async` produces suspendable functions that return promises. `suspendable` returns a promise that is fulfilled with `defn`'s return value, or rejected with `defn`'s exception. Other ways of communicating results/errors are also supported:
211
212- Returning a promise: `suspendable(1, 2).then(function (val) {...}, function (err) {...});`
213- Acceptng a node-style callback: `suspendable2(1, 2, function (err, val) {...});`
214- returning a lazily-executed thunk: `suspendable3(1, 2)(function (err, val) {...});`
215- returning the value directly: `try { var val = suspendable4(1, 2); } catch (err) {...}`
216
217Note that `suspendable4` can only be called from inside another suspendable function. Also, it is possible to create suspendable functions that comminucate results in multiple ways, such as both accepting a callback and returning a promise. You can use the [`async.mod`](#the-asyncmod-function) function to achieve this.
218
219### Preservation of `this` Context
220When a suspendable function is called, its `this` context is passed through to the call to its definition. For example, when `suspendable.call(myObj, 1, 2)` is executed, `defn` will be called with arguments `1` and `2` and a `this` value of `myObj`.
221
222### Creating and Using Asynchronous Iterators
223The `async` function can be used to create asynchronous iterators. These are analogous to [ES6 iterators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol), except that the `next()` function is a suspendable function obeying all the rules described in this section. `async.iterable` creates an iterable which returns an asynchronous iterator whose `next()` function returns a promise of a `{value, done}` result.
224
225Asynchronous iterators have a `forEach()` method for iterating over their values. For more information, take a look at the [descendentFilePaths.js](./examples/descendentFilePaths.js) and [iteration.js](./examples/iteration.js) examples.
226
227### Eager versus Lazy Execution
228Calling a suspendable function such as `suspendable` starts its asynchronous execution immediately, as per the normal semantics of promises. In contrast, thunk-returning suspendable functions do not begin executing until a callback is passed to the thunk. Suspendable functions such as `suspendable3` thus have lazy semantics.
229
230### Nesting, Composition and Recursion
231Suspendable functions may be called in `await` expressions, since they return promises (or thunks or values) and are therefore [awaitable](#what-works-with-await). It follows that calls to suspendable functions may be arbitrarily nested and composed, and may be recursive.
232
233### The `async.mod` Function
234Every variant of the `async` function (i.e. `async`, `async.cps`, `async.iterable`, etc) has a `mod` method that accepts an `options` object and returns another `async` function variant. The `options` object may contain any combination of the following four properties:
235
236```javascript
237{
238 returnValue: <string>; // Recognised values: 'none', 'promise', 'thunk', 'result'
239 acceptsCallback: <boolean>;
240 isIterable: <boolean>;
241 maxConcurrency: <number>; // Recognised values: falsy values and positive numbers
242}
243```
244Omitted properties will inherit their value from the `async` variant being modded. For example, the calls `async.mod({acceptsCallback:true})` and `async.cps.mod({returnValue:'promise'})` are equivalent. Both calls return an `async` function that may be used to create suspendable functions that both accept a callback and return a promise.
245
246
247
248# 8. `await` in Depth: Awaitable Expressions
249The subsections below refer to the following code:
250```javascript
251var suspendable = async (function () {
252 var promise1 = new Promise(.../* eventually produces the value 'p1' */);
253 var promise2 = new Promise(.../* eventually produces the value 'p2' */);
254 var thunk1 = function(callback) {.../* eventually produces the value 't1' */});
255 var thunk2 = function(callback) {.../* eventually produces the value 't2' */});
256 var thunk3 = ..., thunk4 = ...;
257 var r1 = await (promise1);
258 var r2 = await (thunk1);
259 var r3 = await (3.14);
260 var r4 = await ([promise2, 2, ['222', thunk2]]);
261 var r5 = await ({ t3: thunk3, t4: thunk4 });
262 return [r1, r2, r3, r4, r5];
263});
264```
265
266### What Works with `await`?
267`await` takes a single argument, which must be an awaitable expression. An awaitable expression may be any of the following:
268
2691. A [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) (or any [`then`able object](http://wiki.commonjs.org/wiki/Promises/A)), as in `var r1 = await (promise1)`. The function `suspendable` will be suspended until `promise1` is settled. The promise's resolution value (`'p1'`) will become the `await` call's return value, and assigned to `r1`. If `promise1` is rejected, the rejection value will be thrown as an exception inside `suspendable`.
2702. A [thunk](https://github.com/visionmedia/co#thunks-vs-promises), as in `var r2 = await (thunk1)`. The thunk `thunk1` will be called immediately, and `suspendable` will be suspended until control is returned to the thunk's callback. The thunk's result (`'t1'`) will become the `await` call's return value, and assigned to `r2`. If `thunk1` returns an error, the error value will be thrown as an exception inside `suspendable`.
2713. A primitive value, such as a number, string or null, as in `var r3 = await (3.14)`. The `await` call will return immediately with the primitive value, in this case assigning the value `3.14` to `r3`.
2724. An array or [plain object](http://lodash.com/docs#isPlainObject), whose elements are all awaitables, as in `var r4 = await ([promise2, 2, ['222', thunk2]])`. Note this definition is recursive and allows nested object graphs. The function `suspendable` will be suspended until all contained awaitables (`promise2`, `2`, `'222'` and `thunk2`) have produced their value, at which time the `await` call will return a clone of the object graph with all awaitable expressions replaced by their results (`['p2', 2 ['222', 't2']]`). If any of the contained awaitables produces an error, the error value will be thrown as an exception in `suspendable`.
273
274Note that calling `await` with more than one argument (or with zero arguments) is equivalent to calling `await` with a single array containing all the arguments.
275
276### Obtaining Awaitable Versions of Node-Style APIs
277In conventional Node.js code, asynchronous functions take a callback as their last parameter and don't return any value. Therefore, calls to these functions are **not awaitable**. However, awaitable versions may be obtained with relative ease using something like [`bluebird's`](https://github.com/petkaantonov/bluebird/) [`promisifyAll()`](https://github.com/petkaantonov/bluebird/blob/master/API.md#promisepromisifyallobject-target---object), or [`thunkify`](https://github.com/visionmedia/node-thunkify).
278
279### Maximising Concurrency
280A series of `await` calls are executed serially. For example, execution of `var r1 = await (promise1)` is completed before execution of `var r2 = await (thunk1)` begins.
281
282In contrast, a single `await` call on an array or plain object processes all of the contained awaitables concurrently. For example, when the statement `var r5 = await ({ t3: thunk3, t4: thunk4 })` both `thunk3` and `thunk4` are called immediately, and their asynchronous tasks are executed concurrently.
283
284Libraries such as [lodash](http://lodash.com) and [underscore](http://underscorejs.org/) interoperate smoothly with `asyncawait`, for both producing arrays of concurrently executing tasks, and for consuming arrays of results.
285
286### Variations of `await`
287There are several variations of the `await` function, with alternative behaviour when the awaitable expression is an array or plain object. Take a look at [awaitTop.js](./examples/awaitTop.js) for a usage example.
288
289The `await.top(n)` variant accepts a number `n`, and resumes the suspendable function when the first `n` awaitable expressions contained in the awaitable array or plain object produce their value. The return value of the `await.top(n)` call is an array containing the fastest `n` results in the order they were resolved.
290
291The `await.in` variant is like `await`, but does not clone the awaitable expression it recieves as an argument. The results of the contained awaitables are substituted in place into the original awaitable array or plain object, which becomes the return value of the `await` call.
292
293
294
295# 9. Recipes
296
297### Handling HTTP Routes with Express
298Coming soon...
299
300### Asynchronous Testing with Mocha
301Coming soon...
302
303
304
305# 10. API Reference
306
307### `function async(fn: Function) --> (...args) --> Promise`
308Creates a function that can be suspended at each asynchronous operation. `fn` contains the body of the suspendable function. `async` returns a function of the form `(...args) --> Promise`. Any arguments passed to this function are passed through to `fn`. The returned promise is resolved when `fn` returns, or rejected if `fn` throws.
309
310### `function async.cps(fn: Function) --> (...args, callback) --> void`
311Variant of `async` that produces a suspendable function that accepts a node-style callback and returns nothing. See [Obtaining Results from Suspendable Functions](#obtaining-results-from-suspendable-functions).
312
313### `function async.thunk(fn: Function) --> (...args) --> Thunk`
314Variant of `async` that produces a suspendable function that returns a thunk. See [Obtaining Results from Suspendable Functions](#obtaining-results-from-suspendable-functions).
315
316### `function async.result(fn: Function) --> (...args) --> any`
317Variant of `async` that produces a suspendable function that returns its result directly, but can only be called from inside another suspendable function. See [Obtaining Results from Suspendable Functions](#obtaining-results-from-suspendable-functions).
318
319### `function async.iterable(fn: Function) --> (...args) --> AsyncIterator`
320Variant of `async` that produces a function which returns an asynchronous iterator, whose `next()` method is a suspendable function that returns a promise. See [Creating and Using Asynchronous Iterators](#creating-and-using-asynchronous-iterators).
321
322### `function async.mod(options) --> AsyncFunction`
323Enables the creation of arbitrary variants of the `async` function. Accepts an `options` object and returns an `async` function variant. See [The `async.mod` Function](#the-asyncmod-function).
324
325### `function await(expr: Awaitable) --> Any`
326Suspends a suspendable function until the [awaitable](#what-works-with-await) expression `expr` produces a result. The result becomes the return value of the `await` call. If `expr` produces an error, then an exception is raised in the suspendable function.
327
328### `function await.top(n: number) --> (expr: Array|Object) --> Array`
329Variant of `await` whose result consists of the `n` fastest-resolving awaitables contained in its argument. See [Variations of `await`](#variations-of-await).
330
331### `function await.in(expr: Array|Object) --> Array|Object`
332Variant of `await` that returns the original array/object, rather than a cloned array/object, substituting the results of contained awaitables in-place. See [Variations of `await`](#variations-of-await).
333
334
335
336# 11. Acknowledgements
337`asyncawait` uses the following technologies:
338
339- [node-fibers](https://github.com/laverdet/node-fibers): This implementation of coroutines is unfortunately limited to Node.js. ES6 generators may be simpler, but fibers are more flexible and support a far broader space of design possibilities. It would be great if ES6 generators were this open and flexible.
340- [bluebird](https://github.com/petkaantonov/bluebird): this promise library is both a core component of `asyncawait` and a great source of inspiration for writing high-performance JavaScript code.
341- [TypeScript](http://www.typescriptlang.org/): `asyncawait` is written in TypeScript (look in the [src folder](./src)), and includes a [type declaration file](./src/typings/asyncawait/asyncawait.d.ts). TypeScript makes JavaScript development faster, less error-prone, more scaleable, and generally more pleasant.
342- [lodash](http://lodash.com/): underscore, but better.
343
344
345# 12. License
346Copyright (c) 2014-2015 Troy Gerwien
347
348Permission is hereby granted, free of charge, to any person obtaining a copy
349of this software and associated documentation files (the "Software"), to deal
350in the Software without restriction, including without limitation the rights
351to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
352copies of the Software, and to permit persons to whom the Software is
353furnished to do so, subject to the following conditions:
354
355The above copyright notice and this permission notice shall be included in
356all copies or substantial portions of the Software.
357
358THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
359IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
360FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
361AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
362LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
363OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
364THE SOFTWARE.