@vnejs/semaphore 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +15 -0
- package/dist/index.js +53 -0
- package/dist/queue-entry.d.ts +8 -0
- package/dist/queue-entry.js +1 -0
- package/dist/utils.d.ts +12 -0
- package/dist/utils.js +14 -0
- package/package.json +22 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { QueueEntry } from "./queue-entry.js";
|
|
2
|
+
export declare class Semaphore {
|
|
3
|
+
queue: Record<string, QueueEntry>;
|
|
4
|
+
queueCurrent: QueueEntry[];
|
|
5
|
+
queueSorted: QueueEntry[];
|
|
6
|
+
length: number;
|
|
7
|
+
weight: number;
|
|
8
|
+
maxWeight: number;
|
|
9
|
+
isQueueStarted: boolean;
|
|
10
|
+
constructor(maxWeight: number);
|
|
11
|
+
push: (key: string, weight: number, func: () => Promise<unknown>) => Promise<void>;
|
|
12
|
+
waitAll: () => Promise<void[]>;
|
|
13
|
+
private startQueue;
|
|
14
|
+
private start;
|
|
15
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createQueueEntry, getPromiseField, isCanAddNewElement, race, recalcSortedQueue } from "./utils.js";
|
|
2
|
+
export class Semaphore {
|
|
3
|
+
queue = {};
|
|
4
|
+
queueCurrent = [];
|
|
5
|
+
queueSorted = [];
|
|
6
|
+
length = 0;
|
|
7
|
+
weight = 0;
|
|
8
|
+
maxWeight = 999;
|
|
9
|
+
isQueueStarted = false;
|
|
10
|
+
constructor(maxWeight) {
|
|
11
|
+
this.maxWeight = maxWeight;
|
|
12
|
+
}
|
|
13
|
+
push = (key, weight, func) => {
|
|
14
|
+
const element = this.queue[key];
|
|
15
|
+
if (element) {
|
|
16
|
+
if (element.weight > weight && !element.inProcess)
|
|
17
|
+
Object.assign(element, { weight, func });
|
|
18
|
+
return element.promise;
|
|
19
|
+
}
|
|
20
|
+
const obj = createQueueEntry(key, weight, func);
|
|
21
|
+
this.queueSorted = [];
|
|
22
|
+
this.queue[key] = obj;
|
|
23
|
+
this.length++;
|
|
24
|
+
!this.isQueueStarted && void this.startQueue();
|
|
25
|
+
return obj.promise;
|
|
26
|
+
};
|
|
27
|
+
waitAll = () => Promise.all(this.queueCurrent.map(getPromiseField));
|
|
28
|
+
async startQueue() {
|
|
29
|
+
this.isQueueStarted = true;
|
|
30
|
+
while (this.length) {
|
|
31
|
+
this.queueSorted = this.queueSorted.length ? this.queueSorted : recalcSortedQueue(this.queue);
|
|
32
|
+
while (isCanAddNewElement(this.queueSorted, this.weight, this.maxWeight)) {
|
|
33
|
+
const entry = this.queueSorted.pop();
|
|
34
|
+
if (entry)
|
|
35
|
+
this.start(entry);
|
|
36
|
+
}
|
|
37
|
+
await race(this.queueCurrent);
|
|
38
|
+
}
|
|
39
|
+
this.isQueueStarted = false;
|
|
40
|
+
}
|
|
41
|
+
start(e) {
|
|
42
|
+
this.weight += e.weight;
|
|
43
|
+
e.inProcess = true;
|
|
44
|
+
this.queueCurrent.push(e);
|
|
45
|
+
e.func().then(() => {
|
|
46
|
+
this.weight -= e.weight;
|
|
47
|
+
this.queueCurrent = this.queueCurrent.filter((a) => a.key !== e.key);
|
|
48
|
+
this.length--;
|
|
49
|
+
delete this.queue[e.key];
|
|
50
|
+
e.resolve?.();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { QueueEntry } from "./queue-entry.js";
|
|
2
|
+
export declare const getPromiseField: (e: QueueEntry) => Promise<void>;
|
|
3
|
+
export declare const onlyNotInProcessWithResolve: (e: QueueEntry) => e is QueueEntry & {
|
|
4
|
+
resolve: () => void;
|
|
5
|
+
};
|
|
6
|
+
export declare const byWeight: (a: QueueEntry, b: QueueEntry) => number;
|
|
7
|
+
export declare const race: (entries: QueueEntry[]) => Promise<void>;
|
|
8
|
+
export declare const createQueueEntry: (key: string, weight: number, func: () => Promise<unknown>) => QueueEntry;
|
|
9
|
+
export declare const isCanAddNewElement: (queue: QueueEntry[], weight: number, maxWeight: number) => boolean;
|
|
10
|
+
export declare const recalcSortedQueue: (queue: Record<string, QueueEntry>) => (QueueEntry & {
|
|
11
|
+
resolve: () => void;
|
|
12
|
+
})[];
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const getPromiseField = (e) => e.promise;
|
|
2
|
+
export const onlyNotInProcessWithResolve = (e) => !e.inProcess && e.resolve !== undefined;
|
|
3
|
+
export const byWeight = (a, b) => b.weight - a.weight;
|
|
4
|
+
export const race = (entries) => entries.length ? Promise.race(entries.map(getPromiseField)) : new Promise((resolve) => setTimeout(resolve, 0));
|
|
5
|
+
export const createQueueEntry = (key, weight, func) => {
|
|
6
|
+
const obj = { key, weight, func, inProcess: false };
|
|
7
|
+
const promise = new Promise((resolve) => {
|
|
8
|
+
obj.resolve = resolve;
|
|
9
|
+
});
|
|
10
|
+
obj.promise = promise;
|
|
11
|
+
return obj;
|
|
12
|
+
};
|
|
13
|
+
export const isCanAddNewElement = (queue, weight, maxWeight) => queue.length > 0 && maxWeight >= weight + queue[queue.length - 1].weight;
|
|
14
|
+
export const recalcSortedQueue = (queue) => Object.values(queue).filter(onlyNotInProcessWithResolve).sort(byWeight);
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vnejs/semaphore",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
12
|
+
"build": "tsc -p tsconfig.json",
|
|
13
|
+
"publish:major": "npm run build && npm version major && npm publish --access public",
|
|
14
|
+
"publish:minor": "npm run build && npm version minor && npm publish --access public",
|
|
15
|
+
"publish:patch": "npm run build && npm version patch && npm publish --access public"
|
|
16
|
+
},
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "ISC",
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"typescript": "^6.0.3"
|
|
21
|
+
}
|
|
22
|
+
}
|