README
asynco
Asynco provides a coroutine-based solution for JavaScript asynchronous programming, its basic features are as follows:
- Universal: Supports but doesn't rely on
Promise
, all the callback APIs(e.g.,fs.readFile
) can be used directly in coroutines. - Performant: Excellent performance, see about performance.
- Flexible: Coroutines are cancellable, can have timeout, can be started in multiple ways, etc.
- Easy-to-use: Pays attention to the conciseness and reasonability of usage and APIs, keeps the basic behavior consistent with
async function
, fully compatible withasync function
. - Lightweight: 8.4kb min, no dependencies.
Compatibility
It is compatible with all JavaScript environments supporting ECMAScript 5
and GeneratorFunction
. The latter can be supported natively or by transpilers such as babel and regenerator.
In the dist/ directory you will find the UMD build(asynco.js), the ES Module build(asynco.esm.js) and their compressed builds respectively.
Installation
Via npm
$ npm i asynco --save
Via yarn
$ yarn add asynco
Via cdn
https://unpkg.com/asynco/dist/asynco.js
API docs
Quick start
Step 1: Preparation
var asynco = require('asynco'); // or `import asynco from 'asynco';`
// if you want to use callback APIs directly in coroutines, just creat a callback proxy, then use it everywhere
var cb = asynco.callbackProxy();
// extend Generator in order to get the best programming experience, this is optional
asynco.extendGenerator();
Step 2: Define a coroutine function
Just define a generator function
with */yield
, in almost the same way of deining an async function
with async/await
:
function* demo() {
// returns a single value
var data = yield fs.readFile('/somefile', 'utf8', cb());
// returns multiple value
var [stdout, stderr] = yield child_process.exec('ls /home', cb('all'));
// returns raw arguments of the callback, now you get a way to handle errors without `try/catch`
var [err, stat] = yield fs.stat('/somefile', cb('raw'));
if (!err && stat.isFile()) {
console.log('It is a file.');
}
// returns a boolean value indicating whether the async operation succeed or not
if (yield fs.access('/somefile', cb('bool'))) {
console.log('The file is accessible.');
}
// use with 3rd-party control flow packages seamlessly, e.g., async
var contents = yield async.mapLimit(['file1', 'file2', 'file3'], 2, (file, callback) => {
fs.readFile(file, 'utf8', callback);
}, cb());
// yield promises
var value = yield Promise.resolve('value');
async function welcome(name) {
return `Welcome, ${name}`;
}
console.log(yield welcome('Sherry')); // Welcome, Sherry
// yield generators
function* hello(name) {
return `Hello, ${name}`;
}
console.log(yield hello('Sherry')); // Hello, Sherry
return 'whatever';
}
Setp 3: Start a coroutine
The extended Generator
has several instance methods for coroutine manipulation:
// start it with a callback
demo('some', 'args').end((err, ret) => {
if (err) throw err;
console.log(ret); // 'whatever'
});
// use it as a thenable object
demo('some', 'args').then(ret => {
// ...
}).catch(err => {
// ...
});
// use it in an async function
async function test() {
await demo('some', 'args');
}
If you don't want to extend Generator
globally, here is an alternative:
var demo = asynco(function* () {
// ...
});
demo().end((err, ret) => {
// ...
});
About performance
- As you can see, asynco fully supports
Promise
, but it is obviously more efficient and memory-saving when using basic callback APIs. - Even if use
Promise
completely, asynco still has almost the same performance asasync function
in the test of recent releases of node.js.