Skip to content

Commit 6ffd4db

Browse files
refact: Migrate $helper.queue to TypeScript (#7981)
1 parent e392165 commit 6ffd4db

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

panel/src/helpers/queue.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { describe, expect, it } from "vitest";
2+
import queue from "./queue";
3+
4+
describe("queue()", () => {
5+
it("should resolve with results for all tasks", async () => {
6+
const results = await queue([
7+
() => Promise.resolve(1),
8+
() => Promise.resolve(2),
9+
() => Promise.resolve(3)
10+
]);
11+
12+
expect(results).toEqual([1, 2, 3]);
13+
});
14+
15+
it("should resolve with an empty array for no tasks", async () => {
16+
const results = await queue([]);
17+
18+
expect(results).toEqual([]);
19+
});
20+
21+
it("should preserve the order of results regardless of completion order", async () => {
22+
const results = await queue([
23+
() => new Promise<number>((resolve) => setTimeout(() => resolve(1), 30)),
24+
() => new Promise<number>((resolve) => setTimeout(() => resolve(2), 20)),
25+
() => new Promise<number>((resolve) => setTimeout(() => resolve(3), 10))
26+
]);
27+
28+
expect(results).toEqual([1, 2, 3]);
29+
});
30+
31+
it("should not exceed the concurrency limit", async () => {
32+
let active = 0;
33+
let maxActive = 0;
34+
const task = () =>
35+
new Promise<void>((resolve) => {
36+
active++;
37+
maxActive = Math.max(maxActive, active);
38+
setTimeout(() => {
39+
active--;
40+
resolve();
41+
}, 10);
42+
});
43+
44+
await queue(
45+
Array.from({ length: 6 }, () => task),
46+
2
47+
);
48+
49+
expect(maxActive).toBeLessThanOrEqual(2);
50+
});
51+
52+
it("should capture rejected tasks as results", async () => {
53+
const error = new Error("task failed");
54+
const results = await queue([
55+
() => Promise.resolve(1),
56+
() => Promise.reject(error),
57+
() => Promise.resolve(3)
58+
]);
59+
60+
expect(results).toEqual([1, error, 3]);
61+
});
62+
});
Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,24 @@
22
* Async function that runs a list of async functions
33
* with a max number of concurrent tasks
44
*
5-
* @param {Array} tasks list of async functions
6-
* @param {Number} concurrent max number of concurrent tasks
7-
* @returns {Promise<Array>}
5+
* @example
6+
* const tasks = urls.map((url) => () => fetch(url))
7+
* await queue(tasks, 5) // runs at most 5 fetches concurrently
8+
*
9+
* @param tasks - list of async functions
10+
* @param concurrent - max number of concurrent tasks
811
*/
9-
export default async function (tasks, concurrent = 20) {
12+
export default async function <T>(
13+
tasks: (() => Promise<T>)[],
14+
concurrent: number = 20
15+
): Promise<T[]> {
16+
const results: T[] = [];
1017
let active = 0;
1118
let index = 0;
1219

1320
return new Promise((done) => {
14-
const resolve = (index) => (result) => {
15-
tasks[index] = result;
21+
const resolve = (index: number) => (result: T) => {
22+
results[index] = result;
1623
active--;
1724
next();
1825
};
@@ -26,7 +33,7 @@ export default async function (tasks, concurrent = 20) {
2633
}
2734

2835
if (active === 0 && index === tasks.length) {
29-
done(tasks);
36+
done(results);
3037
}
3138
};
3239

panel/src/panel/upload.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { reactive } from "vue";
22
import { uuid } from "@/helpers/string";
33
import State from "./state.js";
44
import listeners from "./listeners.js";
5-
import queue from "@/helpers/queue.js";
5+
import queue from "@/helpers/queue";
66
import { uploadAsChunks } from "@/helpers/upload.js";
77
import { extension, name, niceSize } from "@/helpers/file.js";
88

0 commit comments

Comments
 (0)