batchloader
Advanced tools
Comparing version 0.0.5 to 0.0.6
@@ -9,5 +9,6 @@ import { MappedBatchLoader } from './mappedbatchloader'; | ||
protected batchDelay: number; | ||
protected batchSize: number; | ||
protected queuedKeys: Key[]; | ||
protected batchPromise: Promise<Value[]> | null; | ||
constructor(batchFn: BatchLoadFn<Key, Value>, keyToUniqueId: KeyToUniqueId<Key> | null, batchDelay?: number); | ||
constructor(batchFn: BatchLoadFn<Key, Value>, keyToUniqueId: KeyToUniqueId<Key> | null, batchDelay?: number, batchSize?: number); | ||
load(key: Key): Promise<Value>; | ||
@@ -18,2 +19,4 @@ loadMany(keys: Key[]): Promise<Value[]>; | ||
protected runBatchNow(): Promise<Value[]>; | ||
private maybeBatchInChunks; | ||
private batchInChunks; | ||
} |
@@ -12,7 +12,11 @@ "use strict"; | ||
const mappedbatchloader_1 = require("./mappedbatchloader"); | ||
const sleep = (ms) => new Promise((resolve) => { | ||
setTimeout(resolve, ms); | ||
}); | ||
class BatchLoader { | ||
constructor(batchFn, keyToUniqueId, batchDelay = 0) { | ||
constructor(batchFn, keyToUniqueId, batchDelay = 0, batchSize = Number.MAX_SAFE_INTEGER) { | ||
this.batchFn = batchFn; | ||
this.keyToUniqueId = keyToUniqueId; | ||
this.batchDelay = batchDelay; | ||
this.batchSize = batchSize; | ||
this.queuedKeys = []; | ||
@@ -33,3 +37,3 @@ this.batchPromise = null; | ||
const { length } = keys; | ||
return this.triggerBatch().then((values) => values.slice(index, length)); | ||
return this.triggerBatch().then((values) => values.slice(index, index + length)); | ||
} | ||
@@ -73,10 +77,38 @@ return Promise.resolve([]); | ||
}); | ||
const values = yield this.batchFn(uniqueKeys); | ||
const values = yield this.maybeBatchInChunks(uniqueKeys); | ||
return queuedKeys.map((_key, i) => values[idToNewIndex[indexToId[i]]]); | ||
} | ||
return this.batchFn(queuedKeys); | ||
return this.maybeBatchInChunks(queuedKeys); | ||
}); | ||
} | ||
maybeBatchInChunks(keys) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (keys.length <= this.batchSize) { | ||
return this.batchFn(keys); | ||
} | ||
return this.batchInChunks(keys); | ||
}); | ||
} | ||
batchInChunks(keys) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { batchSize, batchDelay } = this; | ||
const promises = []; | ||
const kLen = keys.length; | ||
for (let i = 0; i < kLen; i += batchSize) { | ||
promises.push(this.batchFn(keys.slice(i, i + batchSize))); | ||
if (batchDelay) { | ||
yield sleep(batchDelay); | ||
} | ||
} | ||
const results = yield Promise.all(promises); | ||
const rLen = results.length; | ||
let values = []; | ||
for (let i = 0; i < rLen; i += 1) { | ||
values = values.concat(results[i]); | ||
} | ||
return values; | ||
}); | ||
} | ||
} | ||
exports.BatchLoader = BatchLoader; | ||
//# sourceMappingURL=batchloader.js.map |
@@ -6,1 +6,2 @@ export interface IBatchLoader<Key, Value> { | ||
} | ||
export declare type MaybePromise<T> = T | Promise<T>; |
{ | ||
"name": "batchloader", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "BatchLoader is a utility for data fetching layer to reduce requests via batching written in TypeScript. Inspired by Facebook's DataLoader", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -99,2 +99,28 @@ import { BatchLoader } from './batchloader'; | ||
test('batchSize', async () => { | ||
const idss = [] as number[][]; | ||
const loader = new BatchLoader( | ||
(ids: number[]): Promise<number[]> => | ||
new Promise( | ||
(resolve): void => { | ||
idss.push(ids); | ||
setTimeout(() => resolve(ids.map((i) => i * 2)), 10); | ||
} | ||
), | ||
String, | ||
10, | ||
2 | ||
); | ||
expect( | ||
await Promise.all([ | ||
loader.load(1), | ||
loader.load(2), | ||
loader.loadMany([3, 4, 5]), | ||
loader.load(6), | ||
loader.loadMany([7, 8]), | ||
]) | ||
).toEqual([2, 4, [6, 8, 10], 12, [14, 16]]); | ||
}); | ||
test('sync mapLoader', async () => { | ||
@@ -101,0 +127,0 @@ const idss = [] as number[][]; |
import { MappedBatchLoader } from 'src/mappedbatchloader'; | ||
import { IBatchLoader } from 'src/types'; | ||
import { IBatchLoader, MaybePromise } from 'src/types'; | ||
@@ -10,2 +10,9 @@ export type BatchLoadFn<Key, Value> = ( | ||
const sleep = (ms: number): Promise<void> => | ||
new Promise( | ||
(resolve): void => { | ||
setTimeout(resolve, ms); | ||
} | ||
); | ||
export class BatchLoader<Key, Value> implements IBatchLoader<Key, Value> { | ||
@@ -18,3 +25,4 @@ protected queuedKeys: Key[] = []; | ||
protected keyToUniqueId: KeyToUniqueId<Key> | null, | ||
protected batchDelay = 0 | ||
protected batchDelay = 0, | ||
protected batchSize = Number.MAX_SAFE_INTEGER | ||
) {} | ||
@@ -37,3 +45,5 @@ | ||
return this.triggerBatch().then((values) => values.slice(index, length)); | ||
return this.triggerBatch().then((values) => | ||
values.slice(index, index + length) | ||
); | ||
} | ||
@@ -90,3 +100,3 @@ return Promise.resolve([]); | ||
const values = await this.batchFn(uniqueKeys); | ||
const values = await this.maybeBatchInChunks(uniqueKeys); | ||
@@ -96,4 +106,33 @@ return queuedKeys.map((_key, i) => values[idToNewIndex[indexToId[i]]]); | ||
return this.batchFn(queuedKeys); | ||
return this.maybeBatchInChunks(queuedKeys); | ||
} | ||
private async maybeBatchInChunks(keys: Key[]): Promise<Value[]> { | ||
if (keys.length <= this.batchSize) { | ||
return this.batchFn(keys); | ||
} | ||
return this.batchInChunks(keys); | ||
} | ||
private async batchInChunks(keys: Key[]): Promise<Value[]> { | ||
const { batchSize, batchDelay } = this; | ||
const promises: Array<MaybePromise<Value[]>> = []; | ||
const kLen = keys.length; | ||
for (let i = 0; i < kLen; i += batchSize) { | ||
promises.push(this.batchFn(keys.slice(i, i + batchSize))); | ||
if (batchDelay) { | ||
await sleep(batchDelay); | ||
} | ||
} | ||
const results = await Promise.all(promises); | ||
const rLen = results.length; | ||
let values: Value[] = []; | ||
for (let i = 0; i < rLen; i += 1) { | ||
values = values.concat(results[i]); | ||
} | ||
return values; | ||
} | ||
} |
@@ -7,15 +7,13 @@ import { BatchLoader } from './batchloader'; | ||
const idss = [] as number[][]; | ||
const loader = new MappedBatchLoader( | ||
new BatchLoader( | ||
(ids: number[]): Promise<number[]> => | ||
new Promise( | ||
(resolve): void => { | ||
idss.push(ids); | ||
setTimeout(() => resolve(ids.map((i) => i * 2)), 10); | ||
} | ||
), | ||
String | ||
), | ||
const loader1 = new BatchLoader( | ||
(ids: number[]): Promise<number[]> => | ||
new Promise( | ||
(resolve): void => { | ||
idss.push(ids); | ||
setTimeout(() => resolve(ids.map((i) => i * 2)), 10); | ||
} | ||
), | ||
String | ||
); | ||
const loader = new MappedBatchLoader(loader1, String); | ||
@@ -44,3 +42,9 @@ expect(await loader.load(3)).toBe('6'); | ||
expect(idss).toEqual([[3], [4], [5], [1, 2, 3], [1, 2, 3], [1, 2, 3]]); | ||
// test one round trip | ||
expect(await Promise.all([loader1.load(1), loader.load(1)])).toEqual([ | ||
2, | ||
'2', | ||
]); | ||
expect(idss).toEqual([[3], [4], [5], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1]]); | ||
}); | ||
@@ -47,0 +51,0 @@ |
@@ -8,1 +8,3 @@ export interface IBatchLoader<Key, Value> { | ||
} | ||
export type MaybePromise<T> = T | Promise<T>; |
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
34432
629