airsync
v2.0.6
Published
⚡ Streamline your code by replacing multiple `await` calls with a single `await` using ༄AirSync, and fully leverage the power of asynchronous, non-blocking I/O.
Downloads
8
Readme
Getting Started
Installation
npm i airsync -S
# or
yarn add airsync
Import
You can use any of these methods to use airsync in your application
// using modules
import { convertFn, resolve } from "airsync";
// or using package
import airsync from "airsync";
// using require
const { convertFn, resolve } = require("airsync");
const airsync = require("airsync");
Introduction
AirSync is a powerful javascript library that you can use when using async
.
The easiest way to see the power of this library is to checkout performance.js
file.
AirSync helps you:
- Create JSON from promises without extracting functions or multiple await
- Convert your existing functions that take promises as parameters, you do not need to wait for promises to fulfil in order to pass them to the function. You can just pass them in as is.
The best part is that AirSync makes your code readable while using full power of non-blocking event based I/O that Node.js is known for.
1. JSON
Problem
const calcAge = async () => 65; // note the async
// this will not result in correct `age`
const props = {
age: calcAge(),
}
// output:
// {age: Promise}
// Promise {<fulfilled>: undefined}
Existing Solution
Either you can write await for each one of the promises, like:
const props = {
age: await calcAge(),
}
Problems with this solution
- This is going to blow out very soon, meaning, as you introduce new calls or fields in this JSON, it will become very unreadable
- The biggest problem with this is performance. This is becoming blocking calls as we are going to await for the results from functions
AirSync Solution
You can use AirSync to solve this issue
const { resolve } = require("airsync");
const props = resolve({
age: calcAge(),
})
Spread Operator
Problem
Lets say you have a code
const encodeKey = async () => {
return { keyId: 123 }
}
and you want to create JSON like:
{
keyId: 123
}
the following WILL NOT create desired result
const result = await resolve({
keyId: encodeKey(),
})
what about this?
const result = await resolve({
...encodeKey(),
})
This is also not going to work because encodeKey()
is an async function.
Existing Solution
We have a solution
const result = await resolve({
...await encodeKey(),
})
Problems with this solution
All of a sudden, our code has to wait for encodeKey
to finish, and if the JSON being produced is long with a lot of await
like this, this is going to be very slow.
AirSync Solution
Luckily, we have spread()
const { spread, resolve } = require('airsync');
const result = await resolve({
[spread()]: encodeKey(),
})
This will result in correct JSON + this code will run asynchronously no matter how many objects are "spreaded".
Try it on RunKit
Max depth
Default object depth supported by airsync is 64
.
2. Async Function
Problem
const getAge = async () => 123;
const getDetail = async (age) => `The age is ${age}`;
await getDetail(getAge());
// output:
// The age is [object Promise]
// Promise {<fulfilled>: undefined}
Existing Solution
Either you can wait for the getAge()
to be resolved first and then pass it to getDetail()
like this:
await getDetail(await getAge());
or you can extract out it to variable.
Problems with this solution
- This is going to blow out very soon, meaning, as you introduce new calls, it will become very unreadable
- The biggest problem with this is performance. This is becoming blocking calls as we are going to await for the results from functions
AirSync Solution
const { convertFn } = require("airsync");
// or you can import using
// const airsync = require('airsync')
// and use airsync.convertFn(...)
const getAge = async () => 123;
const getDetail = convertFn(async (age) => `The age is ${age}`); // notice the wrap around "convertFn"
const result = await getDetail(getAge());
Try it on RunKit
Misc Features
Options
If the first parameter is an object for the convertFn()
, that object is used for setting up the options.
For example:
const getNumb = convertFn(() => 123, {
startTime: res.startTime,
endTime: res.endTime,
});
You can also override the options for a crafted function later.
getNumb.setOptions({
// hint: server-timing
startTime: res.startTime,
endTime: res.endTime,
name: "getNumb",
description: "Get number",
debug: false, // to enable airsync debugging
});
Following are the possible options
| Option | Description |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name
| An identity for the function. Defaults to <function>.name
- IT MUST NOT CONTAIN SPACE |
| description
| A description for the function |
| startTime
| Function for server timing - (name, description) => {}
- the name
and description
is passed back to this function |
| endTime
| Function for server timing - (name) => {}
- the name
is passed back to this function |
| debug
| Boolean value to tell airsync whether debug logging is enabled or not. It will use a global logger.debug()
object. If no such object exists, it will use console.debug()
|
Bulk Export (Advanced)
Converting existing exports to crafted functions is easy, either using convertFn
for each function which can be cumbersome depending on number of functions; or you can simply convert the whole object using a helper function exportFns
.
Let's say you have:
const function1 = () => {};
const function2 = () => {};
module.exports = {
function1,
function2,
};
Just use exportFns
when exporting
const { exportFns } = require("airsync");
const function1 = () => {};
const function2 = () => {};
module.exports = exportFns({
function1,
function2,
});
Alternatively, you can do it when importing like in example of /examples/resolve.js
. Doing it multiple times does not harm.
Get Object Value
If you have a function that returns an object, and you want to grab just one specific value from the object, you can use following get
function to do that.
This function used to be part of library. Since 1.0.4
, the get()
function is removed (see CHANGELOG). However, if you need it, you can add it as utility in your project.
const { get } = require('airsync/get');
This function has peer dependency of lodash.get
const getProfile = async (uid) => ({
name: "John",
age: 45,
father: {
name: "Peter",
},
});
(async () => {
console.log(await get(getProfile(), "father.name")); // output: Peter
console.log(await get(getProfile(), "mother.name", "Steph")); // output: Steph
console.log(await get(getProfile(), "brother.name")); // output: undefined
})();
License
Copyright (c) 2020-present @abumq (Majid Q.)
https://github.com/abumq/airsync
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.