Asyncawait
Callback heaven for Node.js with async/await
Install / Use
/learn @yortus/AsyncawaitREADME
UPDATE June 2018
Do you need this library?
This library has enabled async/await coding style in Node.js since 2014. But JavaScript now has native async/await. JS async/await was standardized as part of ES2017, and has been enabled by default in Node.js since v7.6.
So, do you still need this library? If you are just starting to use async/await, the answer is probably no. Use native async/await. If you're maintaining a codebase that uses this library, or that needs to run on a old version of Node.js, then you may want to keep using it, but consider migrating to native async/await eventually. If you need deep coroutines for an advanced scenario, there may still be a case for using this library, since native async/await only supports shallow coroutine semantics.
Guide to asyncawait v1.0
- Introduction
- Feature/Gotcha Summary
- How Does it Work?
- Compared to...
- Performance
- Quick Start
asyncin Depth: Suspendable Functionsawaitin Depth: Awaitable Expressions- Recipes
- API Reference
- Acknowledgements
- License
1. Introduction
asyncawait addresses the problem of callback hell in Node.js JavaScript code. Inspired by C#'s async/await 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:
var foo = async (function() {
var resultA = await (firstAsyncCall());
var resultB = await (secondAsyncCallUsing(resultA));
var resultC = await (thirdAsyncCallUsing(resultB));
return doSomethingWith(resultC);
});
which, with one proviso, is semantically equivalent to:
function foo2(callback) {
firstAsyncCall(function (err, resultA) {
if (err) { callback(err); return; }
secondAsyncCallUsing(resultA, function (err, resultB) {
if (err) { callback(err); return; }
thirdAsyncCallUsing(resultB, function (err, resultC) {
if (err) {
callback(err);
} else {
callback(null, doSomethingWith(resultC));
}
});
});
});
}
The 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.
In 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 requireing specialised asynchronous control-flow constructs like each and whilst, you can use plain JavaScript constructs like for and while loops.
2. Feature/Gotcha Summary
- Eliminates callback spaghetti code.
- Enables the use of ordinary JavaScript control flow constructs for asynchronous operations.
- Syntax is plain JavaScript, and behaves much like C#'s async/await.
- Seamless interoperation with most other libraries, including Express, Mocha, Underscore, Bluebird, etc.
- Fast and lightweight.
- Completely non-blocking.
- Does not require ES6 generators.
- No code preprocessing or special build steps, simply write and execute your code normally.
- Built with node-fibers.
- TypeScript and X-to-JavaScript friendly (since ES6 generators are not required).
- TypeScript typings are embedded.
- Works only in Node.js, not in browsers (since it uses node-fibers).
3. How does it work?
Like co, asyncawait can suspend a running function without blocking Node's event loop. Both libraries are built on coroutines, but use different technologies. co uses ES6 generators, which work in Node >= v0.11.2 (with the --harmony flag), and will hopefully be supported someday by all popular JavaScript environments and toolchains.
asyncawait uses 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, such as TypeScript or CoffeeScript.
A similar outcome may be achieved by transforming JavaScript source code in a preprocessing step. streamline.js is an example of this method. Code using asyncawait is executed normally without any code tranformation or preprocessing.
4. Compared to...
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, bluebird and 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 folder.
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).
| | 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)
|---|---|---|---|---|
| Plain synchronous code | :heavy_exclamation_mark:<sup>[1]</sup> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Plain callbacks | :white_check_mark: | :heavy_exclamation_mark:<sup>[2]</sup> | :white_check_mark: | :white_check_mark: |
| Callbacks + control-flow (e.g. async) | :white_check_mark: | :heavy_exclamation_mark:<sup>[3]</sup> | :white_check_mark: | :white_check_mark: |
| Promises + control-flow (e.g. bluebird) | :white_check_mark: | :heavy_exclamation_mark:<sup>[3]</sup> | :white_check_mark: | :white_check_mark: |
| Coroutines with co | :white_check_mark: | :white_check_mark: | :heavy_exclamation_mark:<sup>[4]</sup> | :heavy_exclamation_mark:<sup>[5]</sup> |
| Coroutines with asyncawait | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_exclamation_mark:<sup>[6]</sup> |
Footnotes: <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. <sup>[2]</sup> Plain callbacks rapidly become unwieldy for complex asynchronous tasks. See comparison. <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. <sup>[4]</sup> Some tools do not (yet) support ES6 generators, including compile-to-JavaScript languages such as [TypeScript](http://www.typescript
Related Skills
node-connect
331.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
81.5kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
331.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
81.5kCommit, push, and open a PR
