js-flock
![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)
![NPM Package](https://nodei.co/npm/js-flock.png)
Collection of neat modular utilities for bumping up development in NODE and Browser.
Including library
Each method is a separate module, so you can require only the methods that you need or a whole package. By default unmodified ES6 code is loaded, optionally we can include transpiled ES5 code.
Transpiled code is wrapped in UMD and can be loaded in Browser as CommonJs, AMD or as global var.
const sort = require('js-flock/sort');
const sort = require('js-flock/es5/sort');
const jsFlock = require('js-flock');
const jsFlock = require('js-flock/es5');
Methods:
sort
Fast array sorting that outperforms lodash sort by ~2x (in some cases it's more then 5x).
For more information about performance take a look at the benchmark result
here.
- Sorting array of objects (supports comparing by nested object properties)
- Sorting flat arrays
- Sorting by multiple properties
- Undefined and null values are always sorted to bottom of list no matter if ordering is ascending or descending.
- Mutates input array in a same way as native Array.prototype.sort() does.
const sort = require('js-flock/sort');
sort([1, 4, 2]).asc();
sort([1, 4, 2]).desc();
sort(persons).asc((p) => p.firstName.toLowerCase());
sort(persons).desc([
(p) => p.firstName,
(p) => p.lastName,
(p) => p.dob
]);
sort(null).asc();
sort(33).desc();
last
Get the last element of array. If condition is provided get the last element of the
array that meets provided condition or undefined if no elements meets condition.
const last = require('js-flock/last');
last([1, 4, 2]);
const persons = [{ id: 1, name: 'john'}, { id: 2, name: 'john'}, { id: 3, name: 'doe'}]
last(persons)
last(persons, (p) => p.name === 'john')
last(persons, (p) => p.name === 'no-name')
toEnum
Convert object or list of strings to enum representation.
Enum representation is immutable (frozen)
const toEnum = require('js-flock/toEnum');
const vehicleType = toEnum({
CAR: 'C',
TRUCK: 'T',
AIRPLANE: 'A',
HELICOPTER: 'H',
canFly(type) {
return type === this.AIRPLANE || type === this.HELICOPTER;
}
});
const vehicle = getVehicle();
if (vehicle.type === vehicleType.TRUCK) {
}
if (vehicleType.canFly(vehicle.type)) {
}
vehicleType.TRUCK = 'boat';
vehicleType.keys();
vehicleType.values();
vehicleType.exists('C');
vehicleType.exists('something');
vehicleType.haveKey('CAR');
vehicleType.haveKey('something');
const gender = toEnum(['MAN', 'WOMEN', 'OTHER']);
gender.keys();
gender.values();
singular
Creates singular function that after is called can't be called again until it finishes with execution.
Singular function injects done function as a first argument of the original function.
When called done indicates that function has finished with execution and that it can be called again.
For example we will use Vue.js and click handler.
<span @click="startConversation()" role="button"></span>
const singular = require('js-flock/singular');
export default {
methods: {
startConversation: singular(function(done) {
if (this.conversation) {
this.$store.dispatch('Chat/conversation/activate', this.conversation.channelId);
done();
return;
}
ChatService.conversation.createDirect(this.professor.id)
.then((newConversation) => {
this.$store.commit('Chat/conversation/add', newConversation);
this.$store.dispatch('Chat/conversation/activate', newConversation.channelId);
})
.catch((err) => {
Toast.showErrorToast();
this.$log.error(err);
})
.then(done);
})
}
};
waitFor
Wait for task to complete before executing function. This module is useful when there isn't event
you can hook into to signify that a given task is complete. waitFor returns promise that resolves
after check function returns truthy value.
const waitFor = require('js-flock/waitFor');
const options = {
interval: Number,
timeout: Number,
};
waitFor(() => Db.connection, options)
.then((connection) => { })
.catch(() => { });
waitFor(() => document.getElementById('elId'))
.then(($el) => { })
.catch(() => { });
promisify
Promisify error first callback function. Instead of taking a callback, the returned function
will return a promise whose fate is decided by the callback behavior of the given node function.
Promisify returns native Promise (requires Promise polyfill on older browser)
const promisify = require('js-flock/promisify');
const readFile = require("fs").readFile;
const readFileAsync = promisify(readFile);
readFile('test.txt', 'utf8', (err, data) => {
if (err) {
console.log(err);
return;
}
console.log(data);
});
readFileAsync('test.txt', 'utf8')
.then((data) => console.log(data))
.catch((err) => console.log(err));
If callback function is called with multiple success values, the fulfillment value will be the
first fulfillment item.
Setting multiArgs options to true means the resulting promise will always fulfill with
an array of the callback's success value(s). This is needed because promises only support a
single success value while some callback API's have multiple success value.
const fun = (cb) => cb(undefined, 'res1', 'res2');
const funAsync = promisify(fun, { multiArgs: true });
funAsync().then(([r1, r2]) => { });
promisify.all
Promisifies the entire object by going through the object's properties and creating
an async equivalent of each function on the object.
Promisify.all mutates input object by adding promisified versions to object.
It will never overwrite existing properties of object.
By default promisify.all does not loop over object prototype which can be change by providing
{ proto: true } option.
The promisified method name will be the original method name suffixed with suffix (default = 'Async').
const promisify = require('js-flock/promisify');
const fs = promisify.all(require("fs"));
fs.readFileAsync('test.txt', 'utf8')
.then((data) => console.log(data))
.catch((err) => console.log(err));
const withOptions = promisify.all(test, {
suffix: String,
multyArgs: Boolean,
proto: Boolean,
exclude: [String],
include: [String],
});
promisify benchmark
Benchmark has been run on:
- 16 GB Ram
- Intel® Core™ i5-4570 CPU @ 3.20GHz × 4
- Ubuntu 16.04
- Node 8.5.0
Promisify results:
Implementation | ops/sec | total |
---|
js-flock | 10,742,789 ops/sec | fastest |
node-util | 91,949 ops/sec | 116x slower |
bluebird | 59,821 ops/sec | 179x slower |
PromisifyAll results:
Implementation | ops/sec | total |
---|
js-flock | 503,387 ops/se | fastest |
bluebird | 28,754 ops/sec | 17x slower |
To run benchmark on your PC follow steps from below
- git clone https://github.com/snovakovic/js-flock.git
- cd js-flock
- npm install
- npm run benchmark:promisify
collar
Set maximum waiting time for promise to resolve. Reject promise if it's not resolved in that time
const collar = require('js-flock/collar');
const MAX_WAITING_TIME = 500;
collar(Http.get('test-url'), MAX_WAITING_TIME)
.then((response) => { })
.catch((err) => {
if (typeof err === 'object' && err.isStrangled) {
console.log(err.message);
}
});
deepFreeze
Recursively apply Object.freez
const deepFreeze = require('js-flock/deepFreeze');
const person = {
fullName: 'test person',
dob: new Date(),
address: {
country: 'testiland',
city: 'this one'
}
};
Object.freeze(person);
Object.isFrozen(person);
Object.isFrozen(person.address);
deepFreeze(person);
Object.isFrozen(person);
Object.isFrozen(person.address);
By default deepFreeze do not loop over prototype chain.
That behaviour can be overridden by providing { proto: true } option.
const ob1 = { test: { a: 'a' } };
const ob2 = Object.create(ob1);
deepFreeze(ob2);
Object.isFrozen(ob2.test);
deepFreeze(ob2, { proto: true });
Object.isFrozen(ob2.test);
deepSeal
Recursively apply Object.seal.
For example of usage reference deepFreeze
deepPreventExtensions
Recursively apply Object.preventExtensions.
For example of usage reference deepFreeze