generated at
async awaitで何かを待つような処理を同期的に書く

async awaitで何かを待つような処理を同期的に書く

mouse down, move up といったイベントドリブンな処理に基づいて、「canvas内でお絵かき」みたいなしょりを書きたいとする
そういうのを、「マウスをdownして、move(ドラッグ)して、mouseがupするのをまつ」という流れをそのまま同期的に記述できると嬉しい。

js
while(true) { const event = await mouseDownPromise() const downPos = {x: event.clinetX, y: event.clientY } const onMove = () => {/* drag中の処理 downPosも参照できる */} window.addEventListener('mousemove', onMove) const upEvent = await mouseUpPromise() window.removeEventListener('mousemove', onMove) // mouseupがresolveされたらmoveを終了 // mouseup時の処理 }


ちょい改善
これは、down -> move -> up の繰り返しを書いたもの
Promiseを得るのは引数経由で注入するといいだろう
moveする前にupする場合を考えるとraceする必要がある
ts
type Hook = ( waitFor: (key: keyof SVGSVGElementEventMap) => Promise<PointerEvent> ) => void; const hook: Hook = async (waitFor) => { while (true) { const down = await waitFor("pointerdown"); console.log(down); async function loopUntilUp() { while (true) { const e = await Promise.race([ waitFor("pointerup"), waitFor("pointermove"), ]); if (e.type === "pointerup") { return e; } console.log(e.clientX, e.clientY); } } const up = await loopUntilUp(); console.log(up); } };

メリット
サイクルがwhile ループで表現できてる
何らかの数字を保持したいなら、ただ単に変数として保持すればよい
mousedown時のデータは、moveやupのときに、単なる外側スコープの変数として参照できる
mousedown時のeventをawaitしたおかげ
mousedown, move, upのcallback内で外側の変数にデータを保持して、moveやup時にそれを参照するのはmutableで、頭がパンクする
stateとeffectが散り散りにならない
細かい仕様変更がやりやすくなると思う

デメリット
書いてる最中にミスると無限ループが発生してパソコンが熱くなる
whileの宿命
moveとかを毎度promise生成して待ち受けるのがパフォーマンス的に悪いとかあるかなあ?


この書き方はmiyamonzはここから知った
モーダルをまつ
キューを保持して一個ずつ消化する
ユーザの反応で消す
「ユーザがモーダルを消すまで」をpromiseとして抽象化する