@timberio/tools
Advanced tools
Comparing version 0.2.0 to 0.3.0
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
var __importDefault = | ||
(this && this.__importDefault) || | ||
function(mod) { | ||
return mod && mod.__esModule ? mod : { default: mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -10,2 +12,2 @@ const queue_1 = __importDefault(require("./queue")); | ||
exports.makeThrottle = throttle_1.default; | ||
//# sourceMappingURL=index.js.map | ||
//# sourceMappingURL=index.js.map |
@@ -6,23 +6,23 @@ /** | ||
export default class Queue<T> { | ||
/** | ||
* First node in the tree | ||
*/ | ||
private first?; | ||
/** | ||
* Last node in the tree | ||
*/ | ||
private last?; | ||
/** | ||
* Number of items in the queue | ||
*/ | ||
length: number; | ||
/** | ||
* Pushes a value into the queue. | ||
* @param value - Any object to push into the queue | ||
*/ | ||
push(value: any): void; | ||
/** | ||
* Remove a value from the start of the queue (FIFO) and return it | ||
*/ | ||
shift(): T | undefined; | ||
/** | ||
* First node in the tree | ||
*/ | ||
private first?; | ||
/** | ||
* Last node in the tree | ||
*/ | ||
private last?; | ||
/** | ||
* Number of items in the queue | ||
*/ | ||
length: number; | ||
/** | ||
* Pushes a value into the queue. | ||
* @param value - Any object to push into the queue | ||
*/ | ||
push(value: any): void; | ||
/** | ||
* Remove a value from the start of the queue (FIFO) and return it | ||
*/ | ||
shift(): T | undefined; | ||
} |
@@ -8,35 +8,35 @@ "use strict"; | ||
class Queue { | ||
constructor() { | ||
/** | ||
* First node in the tree | ||
*/ | ||
/** | ||
* Number of items in the queue | ||
*/ | ||
this.length = 0; | ||
} | ||
constructor() { | ||
/** | ||
* Pushes a value into the queue. | ||
* @param value - Any object to push into the queue | ||
* First node in the tree | ||
*/ | ||
push(value) { | ||
const node = { value }; | ||
this.last = this.last ? (this.last.next = node) : (this.first = node); | ||
this.length++; | ||
} | ||
/** | ||
* Remove a value from the start of the queue (FIFO) and return it | ||
* Number of items in the queue | ||
*/ | ||
shift() { | ||
if (this.first) { | ||
const { value } = this.first; | ||
this.first = this.first.next; | ||
if (!--this.length) { | ||
this.last = undefined; | ||
} | ||
return value; | ||
} | ||
this.length = 0; | ||
} | ||
/** | ||
* Pushes a value into the queue. | ||
* @param value - Any object to push into the queue | ||
*/ | ||
push(value) { | ||
const node = { value }; | ||
this.last = this.last ? (this.last.next = node) : (this.first = node); | ||
this.length++; | ||
} | ||
/** | ||
* Remove a value from the start of the queue (FIFO) and return it | ||
*/ | ||
shift() { | ||
if (this.first) { | ||
const { value } = this.first; | ||
this.first = this.first.next; | ||
if (!--this.length) { | ||
this.last = undefined; | ||
} | ||
return value; | ||
} | ||
} | ||
} | ||
exports.default = Queue; | ||
//# sourceMappingURL=queue.js.map | ||
//# sourceMappingURL=queue.js.map |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
var __importDefault = | ||
(this && this.__importDefault) || | ||
function(mod) { | ||
return mod && mod.__esModule ? mod : { default: mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const queue_1 = __importDefault(require("./queue")); | ||
describe("queue tests", () => { | ||
it("should store correct number of items in queue", () => { | ||
const q = new queue_1.default(); | ||
const numberOfItems = 10; | ||
for (let i = 0; i < numberOfItems; i++) { | ||
q.push(i); | ||
} | ||
expect(q.length).toEqual(numberOfItems); | ||
it("should store correct number of items in queue", () => { | ||
const q = new queue_1.default(); | ||
const numberOfItems = 10; | ||
for (let i = 0; i < numberOfItems; i++) { | ||
q.push(i); | ||
} | ||
expect(q.length).toEqual(numberOfItems); | ||
}); | ||
it("should retrieve the items in FIFO order", () => { | ||
const q = new queue_1.default(); | ||
const numberOfItems = 10; | ||
const list = []; | ||
// Insert items to both the array and queue | ||
for (let i = 0; i < numberOfItems; i++) { | ||
list.push(i); | ||
q.push(i); | ||
} | ||
// Map over plain array (which is ordered), and test | ||
// against the values from the queue | ||
list.forEach(item => { | ||
expect(q.shift()).toEqual(item); | ||
}); | ||
it("should retrieve the items in FIFO order", () => { | ||
const q = new queue_1.default(); | ||
const numberOfItems = 10; | ||
const list = []; | ||
// Insert items to both the array and queue | ||
for (let i = 0; i < numberOfItems; i++) { | ||
list.push(i); | ||
q.push(i); | ||
} | ||
// Map over plain array (which is ordered), and test | ||
// against the values from the queue | ||
list.forEach(item => { | ||
expect(q.shift()).toEqual(item); | ||
}); | ||
// Queue should now be empty | ||
expect(q.length).toEqual(0); | ||
}); | ||
it("should handle 100,000 items", () => { | ||
const q = new queue_1.default(); | ||
const numberOfItems = 100000; | ||
for (let i = 0; i < numberOfItems; i++) { | ||
q.push(i); | ||
} | ||
expect(q.length).toEqual(numberOfItems); | ||
}); | ||
it("should return undefined if queue is empty", () => { | ||
const q = new queue_1.default(); | ||
expect(q.shift()).toEqual(undefined); | ||
}); | ||
// Queue should now be empty | ||
expect(q.length).toEqual(0); | ||
}); | ||
it("should handle 100,000 items", () => { | ||
const q = new queue_1.default(); | ||
const numberOfItems = 100000; | ||
for (let i = 0; i < numberOfItems; i++) { | ||
q.push(i); | ||
} | ||
expect(q.length).toEqual(numberOfItems); | ||
}); | ||
it("should return undefined if queue is empty", () => { | ||
const q = new queue_1.default(); | ||
expect(q.shift()).toEqual(undefined); | ||
}); | ||
}); | ||
//# sourceMappingURL=queue.test.js.map | ||
//# sourceMappingURL=queue.test.js.map |
@@ -6,2 +6,4 @@ import { InferArgs } from "./types"; | ||
*/ | ||
export default function makeThrottle<T extends (...args: any[]) => any>(max: number): (fn: T) => (...args: InferArgs<T>[]) => Promise<InferArgs<T>>; | ||
export default function makeThrottle<T extends (...args: any[]) => any>( | ||
max: number | ||
): (fn: T) => (...args: InferArgs<T>[]) => Promise<InferArgs<T>>; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
var __importDefault = | ||
(this && this.__importDefault) || | ||
function(mod) { | ||
return mod && mod.__esModule ? mod : { default: mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -20,53 +14,49 @@ const queue_1 = __importDefault(require("./queue")); | ||
function makeThrottle(max) { | ||
// Current iteration cycle | ||
let current = 0; | ||
// Create a FIFO queue | ||
const queue = new queue_1.default(); | ||
/** | ||
* Throttle function that throttles the passed func according to `max` | ||
* @param fn - async function to resolve | ||
*/ | ||
function throttle(fn) { | ||
return (...args) => __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => { | ||
/** | ||
* Handler for resolving the Promise chain | ||
*/ | ||
function handler() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Only resolve if the `max` hasn't been exhausted | ||
if (current < max) { | ||
// Increment the available slot size | ||
current++; | ||
try { | ||
// Await the passed function here first, to determine if any | ||
// errors are thrown, so they can be handled by our outside `reject` | ||
resolve(yield fn(...args)); | ||
} | ||
catch (e) { | ||
reject(e); | ||
} | ||
// Since this has now resolved, make the slot available again | ||
current--; | ||
// If there are items waiting in the queue, resolve the next | ||
// Promise | ||
if (queue.length > 0) { | ||
queue.shift()(); | ||
} | ||
} | ||
else { | ||
// The `max` has been exceeded - push onto the queue to wait | ||
queue.push(handler); | ||
} | ||
}); | ||
} | ||
// Return the async handler | ||
return handler(); | ||
}); | ||
}); | ||
} | ||
// Return the throttle function | ||
return throttle; | ||
// Current iteration cycle | ||
let current = 0; | ||
// Create a FIFO queue | ||
const queue = new queue_1.default(); | ||
/** | ||
* Throttle function that throttles the passed func according to `max` | ||
* @param fn - async function to resolve | ||
*/ | ||
function throttle(fn) { | ||
return async (...args) => { | ||
return new Promise((resolve, reject) => { | ||
/** | ||
* Handler for resolving the Promise chain | ||
*/ | ||
async function handler() { | ||
// Only resolve if the `max` hasn't been exhausted | ||
if (current < max) { | ||
// Increment the available slot size | ||
current++; | ||
try { | ||
// Await the passed function here first, to determine if any | ||
// errors are thrown, so they can be handled by our outside `reject` | ||
resolve(await fn(...args)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
// Since this has now resolved, make the slot available again | ||
current--; | ||
// If there are items waiting in the queue, resolve the next | ||
// Promise | ||
if (queue.length > 0) { | ||
queue.shift()(); | ||
} | ||
} else { | ||
// The `max` has been exceeded - push onto the queue to wait | ||
queue.push(handler); | ||
} | ||
} | ||
// Return the async handler | ||
return handler(); | ||
}); | ||
}; | ||
} | ||
// Return the throttle function | ||
return throttle; | ||
} | ||
exports.default = makeThrottle; | ||
//# sourceMappingURL=throttle.js.map | ||
//# sourceMappingURL=throttle.js.map |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
var __importDefault = | ||
(this && this.__importDefault) || | ||
function(mod) { | ||
return mod && mod.__esModule ? mod : { default: mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const throttle_1 = __importDefault(require("./throttle")); | ||
describe("Throttle tests", () => { | ||
it("should throttle Promises", () => __awaiter(this, void 0, void 0, function* () { | ||
// Fixtures | ||
const max = 2; | ||
const throttleTime = 20; // ms | ||
const numberOfPromises = 10; | ||
// Create the throttle function | ||
const throttle = throttle_1.default(max); | ||
// Create the pipeline function to use the throttle | ||
const pipeline = throttle((log) => __awaiter(this, void 0, void 0, function* () { | ||
return new Promise(resolve => { | ||
setTimeout(() => { | ||
resolve(log); | ||
}, throttleTime); | ||
}); | ||
})); | ||
// Build the promises | ||
const promises = []; | ||
// Start the timer | ||
const start = process.hrtime(); | ||
for (let i = 0; i < numberOfPromises; i++) { | ||
promises.push(pipeline({ message: "Hey" })); | ||
} | ||
// Await until they've all finished | ||
yield Promise.all(promises); | ||
// End the timer | ||
const end = process.hrtime(start)[1] / 1000000; | ||
// Expect time to have taken (numberOfPromises / max) * throttleTime | ||
const expectedTime = (numberOfPromises / max) * throttleTime; | ||
expect(end).toBeGreaterThanOrEqual(expectedTime); | ||
})); | ||
it("should handle rejections", () => __awaiter(this, void 0, void 0, function* () { | ||
// Fixtures | ||
const numberOfPromises = 10; | ||
// Create the throttle function | ||
const throttle = throttle_1.default(5); | ||
// Error counter | ||
let errors = 0; | ||
// Create a throttled function that will throw half the time | ||
const pipeline = throttle((i) => __awaiter(this, void 0, void 0, function* () { | ||
if (i % 2 == 0) { | ||
throw new Error("Thrown inside throttled function!"); | ||
} | ||
return i; | ||
})); | ||
for (let i = 0; i < numberOfPromises; i++) { | ||
yield pipeline(i).catch(() => errors++); | ||
} | ||
expect(errors).toEqual(numberOfPromises / 2); | ||
})); | ||
it("should throttle Promises", async () => { | ||
// Fixtures | ||
const max = 2; | ||
const throttleTime = 20; // ms | ||
const numberOfPromises = 10; | ||
// Create the throttle function | ||
const throttle = throttle_1.default(max); | ||
// Create the pipeline function to use the throttle | ||
const pipeline = throttle( | ||
async log => | ||
new Promise(resolve => { | ||
setTimeout(() => { | ||
resolve(log); | ||
}, throttleTime); | ||
}) | ||
); | ||
// Build the promises | ||
const promises = []; | ||
// Start the timer | ||
const start = process.hrtime(); | ||
for (let i = 0; i < numberOfPromises; i++) { | ||
promises.push(pipeline({ message: "Hey" })); | ||
} | ||
// Await until they've all finished | ||
await Promise.all(promises); | ||
// End the timer | ||
const end = process.hrtime(start)[1] / 1000000; | ||
// Expect time to have taken (numberOfPromises / max) * throttleTime | ||
const expectedTime = (numberOfPromises / max) * throttleTime; | ||
expect(end).toBeGreaterThanOrEqual(expectedTime); | ||
}); | ||
it("should handle rejections", async () => { | ||
// Fixtures | ||
const numberOfPromises = 10; | ||
// Create the throttle function | ||
const throttle = throttle_1.default(5); | ||
// Error counter | ||
let errors = 0; | ||
// Create a throttled function that will throw half the time | ||
const pipeline = throttle(async i => { | ||
if (i % 2 == 0) { | ||
throw new Error("Thrown inside throttled function!"); | ||
} | ||
return i; | ||
}); | ||
for (let i = 0; i < numberOfPromises; i++) { | ||
await pipeline(i).catch(() => errors++); | ||
} | ||
expect(errors).toEqual(numberOfPromises / 2); | ||
}); | ||
}); | ||
//# sourceMappingURL=throttle.test.js.map | ||
//# sourceMappingURL=throttle.test.js.map |
@@ -5,10 +5,10 @@ /** | ||
export interface IQueue<T> { | ||
/** | ||
* Value of queue should be an object | ||
*/ | ||
value: T; | ||
/** | ||
* Leaf node in queue, representing the next value | ||
*/ | ||
next?: IQueue<T>; | ||
/** | ||
* Value of queue should be an object | ||
*/ | ||
value: T; | ||
/** | ||
* Leaf node in queue, representing the next value | ||
*/ | ||
next?: IQueue<T>; | ||
} | ||
@@ -18,2 +18,6 @@ /** | ||
*/ | ||
export declare type InferArgs<T> = T extends (...args: any[]) => Promise<infer U> ? U : void; | ||
export declare type InferArgs<T> = T extends ( | ||
...args: any[] | ||
) => Promise<infer U> | ||
? U | ||
: void; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
//# sourceMappingURL=types.js.map | ||
//# sourceMappingURL=types.js.map |
@@ -1,9 +0,1 @@ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
import Queue from "./queue"; | ||
@@ -24,3 +16,3 @@ /** | ||
function throttle(fn) { | ||
return (...args) => __awaiter(this, void 0, void 0, function* () { | ||
return async (...args) => { | ||
return new Promise((resolve, reject) => { | ||
@@ -30,29 +22,27 @@ /** | ||
*/ | ||
function handler() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Only resolve if the `max` hasn't been exhausted | ||
if (current < max) { | ||
// Increment the available slot size | ||
current++; | ||
try { | ||
// Await the passed function here first, to determine if any | ||
// errors are thrown, so they can be handled by our outside `reject` | ||
resolve(yield fn(...args)); | ||
} | ||
catch (e) { | ||
reject(e); | ||
} | ||
// Since this has now resolved, make the slot available again | ||
current--; | ||
// If there are items waiting in the queue, resolve the next | ||
// Promise | ||
if (queue.length > 0) { | ||
queue.shift()(); | ||
} | ||
async function handler() { | ||
// Only resolve if the `max` hasn't been exhausted | ||
if (current < max) { | ||
// Increment the available slot size | ||
current++; | ||
try { | ||
// Await the passed function here first, to determine if any | ||
// errors are thrown, so they can be handled by our outside `reject` | ||
resolve(await fn(...args)); | ||
} | ||
else { | ||
// The `max` has been exceeded - push onto the queue to wait | ||
queue.push(handler); | ||
catch (e) { | ||
reject(e); | ||
} | ||
}); | ||
// Since this has now resolved, make the slot available again | ||
current--; | ||
// If there are items waiting in the queue, resolve the next | ||
// Promise | ||
if (queue.length > 0) { | ||
queue.shift()(); | ||
} | ||
} | ||
else { | ||
// The `max` has been exceeded - push onto the queue to wait | ||
queue.push(handler); | ||
} | ||
} | ||
@@ -62,3 +52,3 @@ // Return the async handler | ||
}); | ||
}); | ||
}; | ||
} | ||
@@ -65,0 +55,0 @@ // Return the throttle function |
@@ -1,12 +0,4 @@ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
import makeThrottle from "./throttle"; | ||
describe("Throttle tests", () => { | ||
it("should throttle Promises", () => __awaiter(this, void 0, void 0, function* () { | ||
it("should throttle Promises", async () => { | ||
// Fixtures | ||
@@ -19,8 +11,6 @@ const max = 2; | ||
// Create the pipeline function to use the throttle | ||
const pipeline = throttle((log) => __awaiter(this, void 0, void 0, function* () { | ||
return new Promise(resolve => { | ||
setTimeout(() => { | ||
resolve(log); | ||
}, throttleTime); | ||
}); | ||
const pipeline = throttle(async (log) => new Promise(resolve => { | ||
setTimeout(() => { | ||
resolve(log); | ||
}, throttleTime); | ||
})); | ||
@@ -35,3 +25,3 @@ // Build the promises | ||
// Await until they've all finished | ||
yield Promise.all(promises); | ||
await Promise.all(promises); | ||
// End the timer | ||
@@ -42,4 +32,4 @@ const end = process.hrtime(start)[1] / 1000000; | ||
expect(end).toBeGreaterThanOrEqual(expectedTime); | ||
})); | ||
it("should handle rejections", () => __awaiter(this, void 0, void 0, function* () { | ||
}); | ||
it("should handle rejections", async () => { | ||
// Fixtures | ||
@@ -52,3 +42,3 @@ const numberOfPromises = 10; | ||
// Create a throttled function that will throw half the time | ||
const pipeline = throttle((i) => __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = throttle(async (i) => { | ||
if (i % 2 == 0) { | ||
@@ -58,9 +48,9 @@ throw new Error("Thrown inside throttled function!"); | ||
return i; | ||
})); | ||
}); | ||
for (let i = 0; i < numberOfPromises; i++) { | ||
yield pipeline(i).catch(() => errors++); | ||
await pipeline(i).catch(() => errors++); | ||
} | ||
expect(errors).toEqual(numberOfPromises / 2); | ||
})); | ||
}); | ||
}); | ||
//# sourceMappingURL=throttle.test.js.map |
{ | ||
"name": "@timberio/tools", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "Javascript logging tools", | ||
@@ -10,3 +10,3 @@ "main": "dist/cjs/index.js", | ||
"scripts": { | ||
"build": "tsc -p tsconfig.json && tsc -p tsconfig.es6.json", | ||
"build": "tsc && tsc -p tsconfig.es6.json", | ||
"prepublish": "npm run build", | ||
@@ -13,0 +13,0 @@ "test": "jest" |
{ | ||
"compilerOptions": { | ||
/* Basic Options */ | ||
"target": "es2015" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */, | ||
"target": "es2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */, | ||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, | ||
@@ -6,0 +6,0 @@ // "lib": [], /* Specify library files to be included in the compilation. */ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
47532
937