小学社会310824 views
LaTeX963205 views
高校物理160808 views
高校化学2926977 views
小学理科720453 views
小学算数1201510 views
高校生物552189 views
高校国語788848 views
中学英語812311 views
英語614821 views
Help
Tools

English

RAF による mousemove 最適化の要点

問題

mousemove イベントは高頻度で発火(ミリ秒単位)
毎回 DOM 操作(選択範囲レンダリング)すると性能劣化

解決策

requestAnimationFrame (RAF) で描画を間引く

let rafId: number | null = null

element.addEventListener('mousemove', (event) => {
    // 座標を取得
    const coord = getCoordinate(event)
    
    // RAF がすでにスケジュール済みならスキップ
    if (rafId !== null) return
    
    // 次フレームで描画をスケジュール
    rafId = requestAnimationFrame(() => {
        render(coord)  // 描画処理
        rafId = null
    })
})

RAF と mouseup の競合問題

RAF 実行前に mouseup が発火すると、状態が不整合になる

// ❌ 危険な実装
let start: Coord | null = null

mousemove: rafId = requestAnimationFrame(() => {
    setSelection(start, end)  // start が null の可能性
})

mouseup: start = null  // RAF 実行前にリセット

解決:イベント発火時に値をキャプチャ

mousemove: 
    const capturedStart = start
    const capturedEnd = coord
    
    rafId = requestAnimationFrame(() => {
        if (!capturedStart) return  // 防御的チェック
        setSelection(capturedStart, capturedEnd)
    })

mouseup:
    if (rafId !== null) {
        cancelAnimationFrame(rafId)  // 未実行の RAF をキャンセル
        rafId = null
    }
    start = null

重要ポイント

RAF のスキップ: rafId !== null で重複スケジュールを防ぐ
値のキャプチャ: RAF 内で参照する変数はイベント時点でキャプチャ
RAF のクリーンアップ: mouseup / mousedown で未実行の RAF をキャンセル
防御的 null チェック: RAF 内でも念のためガード

効果

描画頻度: 毎ミリ秒 → 60fps(約 16ms ごと)
不要な DOM 操作を削減
滑らかな UI 更新