Skip to content

Commit 3bdc68a

Browse files
authored
Merge pull request #4 from takker99/feature-force-queued
✨ Make specified results queued whatever `maxQueued` is
2 parents a6f9ae1 + e308a78 commit 3bdc68a

File tree

2 files changed

+125
-112
lines changed

2 files changed

+125
-112
lines changed

promisify.test.ts

Lines changed: 102 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2,93 +2,115 @@ import { promisify } from "./promisify.ts";
22
import { assert } from "./deps_test.ts";
33

44
Deno.test("promisify()", async (t) => {
5-
await t.step("keep all results", async () => {
6-
const [get, resolve] = promisify<number>();
5+
await t.step("without forceQueued", async (t) => {
6+
await t.step("keep all results", async () => {
7+
const [get, resolve] = promisify<number>();
78

8-
const pending = get();
9-
resolve(0);
10-
resolve(1);
11-
assert(await pending === 0);
12-
assert(await get() === 1);
13-
resolve(2);
14-
assert(await get() === 2);
15-
resolve(3);
16-
resolve(4);
17-
assert(await get() === 3);
18-
assert(await get() === 4);
19-
resolve(5);
20-
resolve(6);
21-
resolve(7);
22-
assert(await get() === 5);
23-
resolve(8);
24-
assert(await get() === 6);
25-
assert(await get() === 7);
26-
assert(await get() === 8);
27-
});
9+
const pending = get();
10+
resolve(0);
11+
resolve(1);
12+
assert(await pending === 0);
13+
assert(await get() === 1);
14+
resolve(2);
15+
assert(await get() === 2);
16+
resolve(3);
17+
resolve(4);
18+
assert(await get() === 3);
19+
assert(await get() === 4);
20+
resolve(5);
21+
resolve(6);
22+
resolve(7);
23+
assert(await get() === 5);
24+
resolve(8);
25+
assert(await get() === 6);
26+
assert(await get() === 7);
27+
assert(await get() === 8);
28+
});
2829

29-
await t.step("keep nothing", async () => {
30-
const [get, resolve] = promisify<number>({ maxQueued: 0 });
30+
await t.step("keep nothing", async () => {
31+
const [get, resolve] = promisify<number>({ maxQueued: 0 });
3132

32-
let pending = get();
33-
resolve(1);
34-
assert(await pending === 1);
35-
resolve(2);
36-
resolve(3);
37-
pending = get();
38-
resolve(4);
39-
assert(await pending === 4);
40-
pending = get();
41-
resolve(5);
42-
resolve(6);
43-
assert(await pending === 5);
44-
});
33+
let pending = get();
34+
resolve(1);
35+
assert(await pending === 1);
36+
resolve(2);
37+
resolve(3);
38+
pending = get();
39+
resolve(4);
40+
assert(await pending === 4);
41+
pending = get();
42+
resolve(5);
43+
resolve(6);
44+
assert(await pending === 5);
45+
});
46+
47+
await t.step("keep the latest result", async () => {
48+
const [get, resolve] = promisify<number>({ maxQueued: 1 });
49+
50+
let pending = get();
51+
resolve(1);
52+
assert(await pending === 1);
53+
resolve(2);
54+
resolve(3);
55+
assert(await get() === 3);
56+
resolve(4);
57+
resolve(5);
58+
resolve(6);
59+
assert(await get() === 6);
60+
pending = get();
61+
resolve(7);
62+
resolve(8);
63+
resolve(9);
64+
assert(await pending === 7);
65+
assert(await get() === 9);
66+
});
4567

46-
await t.step("keep the latest result", async () => {
47-
const [get, resolve] = promisify<number>({ maxQueued: 1 });
68+
await t.step("keep the latest and second latest results", async () => {
69+
const [get, resolve] = promisify<number>({ maxQueued: 2 });
4870

49-
let pending = get();
50-
resolve(1);
51-
assert(await pending === 1);
52-
resolve(2);
53-
resolve(3);
54-
assert(await get() === 3);
55-
resolve(4);
56-
resolve(5);
57-
resolve(6);
58-
assert(await get() === 6);
59-
pending = get();
60-
resolve(7);
61-
resolve(8);
62-
resolve(9);
63-
assert(await pending === 7);
64-
assert(await get() === 9);
71+
resolve(1);
72+
let pending = get();
73+
assert(await pending === 1);
74+
resolve(2);
75+
resolve(3);
76+
assert(await get() === 2);
77+
assert(await get() === 3);
78+
resolve(4);
79+
resolve(5);
80+
resolve(6);
81+
assert(await get() === 5);
82+
resolve(7);
83+
resolve(8);
84+
assert(await get() === 7);
85+
assert(await get() === 8);
86+
pending = get();
87+
resolve(9);
88+
resolve(10);
89+
resolve(11);
90+
resolve(12);
91+
assert(await pending === 9);
92+
assert(await get() === 11);
93+
assert(await get() === 12);
94+
});
6595
});
6696

67-
await t.step("keep the latest and second latest results", async () => {
68-
const [get, resolve] = promisify<number>({ maxQueued: 2 });
97+
await t.step("with forceQueued", async (t) => {
98+
await t.step("keep the latest result", async () => {
99+
const [get, resolve] = promisify<number>({ maxQueued: 1 });
69100

70-
let pending = get();
71-
resolve(1);
72-
assert(await pending === 1);
73-
resolve(2);
74-
resolve(3);
75-
assert(await get() === 2);
76-
assert(await get() === 3);
77-
resolve(4);
78-
resolve(5);
79-
resolve(6);
80-
assert(await get() === 5);
81-
resolve(7);
82-
resolve(8);
83-
assert(await get() === 7);
84-
assert(await get() === 8);
85-
pending = get();
86-
resolve(9);
87-
resolve(10);
88-
resolve(11);
89-
resolve(12);
90-
assert(await pending === 9);
91-
assert(await get() === 11);
92-
assert(await get() === 12);
101+
resolve(1);
102+
const pending = get();
103+
assert(await pending === 1);
104+
resolve(2);
105+
resolve(20, { forceQueued: true });
106+
resolve(3);
107+
resolve(4);
108+
resolve(30, { forceQueued: true });
109+
resolve(40, { forceQueued: true });
110+
assert(await get() === 20);
111+
assert(await get() === 30);
112+
assert(await get() === 40);
113+
assert(await get() === 4);
114+
});
93115
});
94116
});

promisify.ts

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import type { Result } from "./types.ts";
22

3+
export interface CallbackOptions {
4+
forceQueued?: boolean;
5+
}
6+
37
export interface PromisifyOptions {
48
/** callbackから次の値を取り出すまでに実行されたcallbackの結果を最新でいくつまで保持するかを表す値
59
*
@@ -20,22 +24,22 @@ export function promisify<T, E = unknown>(
2024
options?: PromisifyOptions,
2125
): readonly [
2226
() => Promise<T>,
23-
(value: T) => void,
24-
(reason: E) => void,
27+
(value: T, options?: CallbackOptions) => void,
28+
(reason: E, options?: CallbackOptions) => void,
2529
] {
2630
const maxQueued = options?.maxQueued === undefined
2731
? undefined
2832
: Math.max(0, options.maxQueued);
29-
if (maxQueued === 0) return promisifyWithoutQueue();
3033

3134
const queue = [] as Result<T, E>[];
32-
let _resolve: ((value: T) => void) | undefined;
33-
let _reject: ((value: E) => void) | undefined;
35+
const queue2 = [] as Result<T, E>[];
36+
let _resolve: ((value: T, options?: CallbackOptions) => void) | undefined;
37+
let _reject: ((value: E, options?: CallbackOptions) => void) | undefined;
3438

3539
/** queueから一つ取り出す。空なら_resolveをセットする */
3640
const waitForSettled = async () => {
3741
if (maxQueued !== undefined) queue.splice(0, queue.length - maxQueued);
38-
const value = queue.shift();
42+
const value = queue2.shift() ?? queue.shift();
3943
if (value) {
4044
if (value.success) return value.value;
4145
throw value.reason;
@@ -48,43 +52,30 @@ export function promisify<T, E = unknown>(
4852
},
4953
);
5054
};
51-
const resolve = (value: T) => {
55+
const resolve = (value: T, options?: CallbackOptions) => {
5256
if (!_resolve) {
53-
queue.push({ success: true, value });
57+
if (options?.forceQueued) {
58+
queue2.push({ success: true, value });
59+
} else {
60+
queue.push({ success: true, value });
61+
}
5462
return;
5563
}
5664
_resolve(value);
5765
_resolve = _reject = undefined;
5866
};
59-
const reject = (value: E) => {
67+
const reject = (reason: E, options?: CallbackOptions) => {
6068
if (!_reject) {
61-
queue.push({ success: false, reason: value });
69+
if (options?.forceQueued) {
70+
queue2.push({ success: false, reason });
71+
} else {
72+
queue.push({ success: false, reason });
73+
}
6274
return;
6375
}
64-
_reject(value);
76+
_reject(reason);
6577
_resolve = _reject = undefined;
6678
};
6779

6880
return [waitForSettled, resolve, reject] as const;
6981
}
70-
71-
function promisifyWithoutQueue<T, E = unknown>(): readonly [
72-
() => Promise<T>,
73-
(value: T) => void,
74-
(reason: E) => void,
75-
] {
76-
let _resolve: ((value: T) => void) | undefined;
77-
let _reject: ((value: E) => void) | undefined;
78-
79-
const waitForSettled = () =>
80-
new Promise<T>(
81-
(res, rej) => {
82-
_resolve = res;
83-
_reject = rej;
84-
},
85-
);
86-
const resolve = (value: T) => _resolve?.(value);
87-
const reject = (value: E) => _reject?.(value);
88-
89-
return [waitForSettled, resolve, reject] as const;
90-
}

0 commit comments

Comments
 (0)