generated at
複数回呼び出されるcallbackをPromisicationするやついろいろ
基本
ts
export function getPromiseSettledAnytimes<T, E = unknown>() { let _resolve: ((value: T) => void) | undefined; let _reject: ((value: E) => void) | undefined; const waitForSettled = () => new Promise<T>( (res, rej) => { _resolve = res; _reject = rej; }, ); const resolve = (value: T) => _resolve?.(value); const reject = (reason: E) => _reject?.(reason); return [waitForSettled, resolve, reject] as const; }

callbackをprimisifyする
処理中に入ったeventを全部無視する
ts
const [listenEvent, listener] = getPromiseSettledAnytimes< Event, Error, >(); addEventListener("event", listener); while (true) { const event = await listenEvent(); // ループの終了までに発火したeventは全て破棄する }
発火したすべてのeventを保持する
ts
const queue = [] as ({ success: true, value: T } | { success: false, value: E })[]; let _resolve: ((value: T) => void) | undefined; let _reject: ((value: E) => void) | undefined; const reset = () => _resolve = _reject = undefined; const waitForSettled = () => new Promise<T>( (res, rej) => { if (queue.length > 0) { const value = queue.shift()!; if (value.success) { res(value.value); } else { rej(value.value); } return; } _resolve = res; _reject = rej; }, ); const resolve = (value: T) => { if (_resolve) { _resolve(value); reset(); return; } queue.push({ success: true, value }); }; const reject = (value: E) => if (_reject) { _reject(value); reset(); return; } queue.push({ success: false, value }); }; addEventListener("event", resolve); while (true) { const { value: event } = await waitForSettled(); // ... // この間に発火したイベントも次以降のループで処理する }
最後に発火した未処理eventだけ保持する
↑の queue の最後尾以外を破棄する


Promiseを解決順に返す
Iterable<Promise<T>> AsyncGenerator<{ success: true; value: T; } | { success: false; value: E; }>
ts
type Result<T, E> = { success: true; value: T; } | { success: false; value: E; }; async function* sortSettled<T, E = unknown>( list: Iterable<Promise<T>> ): AsyncGenerator<Result<T, E>, void, unknown> { const queue = [] as Result<T, E>[]; let _resolve: ((value: Result<T, E>) => void) | undefined; /** _resolveがなければqueueに貯め、あれば消費する */ const push = (value: Result<T, E>) => { if (!_resolve) { queue.push(value); return; } _resolve(value); _resolve = undefined; }; /** queueから一つ取り出す。空なら_resolveをセットする */ const shift = async () => queue.length > 0 ? queue.shift()! : await new Promise<Result<T, E>>( (resolve) => _resolve = resolve ); let count = 0; /** Promiseが解決したらqueueにいれるよう仕掛けておく */ for (const item of list) { count++; item.then((value) => push({ success: true, value, })) .catch((reason) => push({ success: false, value: reason as E, })); } /** 終わったものから順次返す */ for (let i = 0; i < count; i++) { yield await shift(); } }

#2022-03-03 00:05:26
#2022-02-12 14:56:56