javascriptで発生するイベントを間引く

近辺で話題になっていたのでまとめた。

イベントを律儀に全て処理しているとattachした即時関数が過剰に実行されてしまう。API通信が大量に発生したり、処理落ちが発生したりする。

lodashunderscoreに実装されている_.throttle_.debounceというファクトリを利用することで、これらをスマートに解決できる。

_.throttle

設定した時間内に2回以上実行されない関数を返すファクトリ。スクロールイベントのような連続量を間引くのに利用される。

$el = $ '#header'
($ window).on 'scroll', ->
  $el.css top: ($ document).scrollTop()

scrollに同期してヘッダを追従させたりする場合、scrollの全フレームを処理しなければいけないような気になる。

しかし、scrollイベントの全フレームを処理しないとカクカクして見えるほど人類のステージは高くない。

$el = $ '#header'
($ window).on 'scroll', _.throttle (event) ->
  $el.css top: ($ document).scrollTop()
, 12

少しだけ間引いてあげればPCも人間もハッピーになれる。12ミリ秒くらいだと殆ど気にならない。24くらいまで増やすと結構気になった。

「だいたい41ミリ秒で24fpsだから41でいいじゃん」と思ったけど元のscrollイベントがアナログ値ではないのでそんなことは全く無かった。

入ってきた連続量の頭(leading-edge)を評価しない、等のオプションがある。詳しくはドキュメントを参照の事。

_.debounce

実行するとタイマーをリセットしてabort、タイマーが切れると実行される関数を返すファクトリ。

($ '#input').on 'keyup', (event) ->
  $el = $ event.currentTarget
  $.ajax '/api/search',
    data: name: $el.val()
    dataType: 'json'
  .done (json) =>
    $el.val json.name if json.name

こんな即時関数を実装してAPIアクセスが大量に発生し、慌ててsetTimeoutで遅延実行するような機構を実装した経験が誰にでもあると思う。

($ '#input').on 'keyup', _.debounce (event) ->
  $el = $ event.currentTarget
  $.ajax '/api/search',
    data: name: $el.val()
    dataType: 'json'
  .done (json) =>
    $el.val json.name if json.name
, 240

これで「最後に実行されてから240ミリ秒以内にもう一度実行されたらabort、実行されなければexec」する即時関数がkeyupにattachされる。

Recent Posts

Loading...

1 Notes

  1. getalog posted this