JavaScriptのイベントを
たくさん見られるサイト

頻度が高いイベントへの対応

イベントにはclickのように扱いやすいものがある一方で、scrollmousemoveなどのように大量に実行されてしまう厄介なものもあります。そのようなイベントをそのまま実装してしまうと不要な呼び出しが多く、動作が重たくなる原因になってしまうので、適度に間引いて処理をしたほうがブラウザに優しいです。

最近のブラウザでは、指定した関数を再描画の前に呼び出してくれるrequestAnimationFrameという便利なメソッドがあるので、それを使用して最適化する例をいくつか載せています。

今では少ないかと思いますが、requestAnimationFrameに対応していない、IE9以前/Android4.3以前などのブラウザにも対応する必要がある場合は、非対応のときにsetTimeoutに置き換えてくれるPolyfillのようなもの使うか、別の実装を検討する必要があります。

Can I use | requestAnimationFrame

scroll

0px

    var isRunning = false

window.addEventListener('scroll', function() {
  // 呼び出されるまで何もしない
  if (!isRunning) {
    isRunning = true

    // 描画する前のタイミングで呼び出してもらう
    window.requestAnimationFrame(function() {

      // ここでなにか処理をする
      console.log(window.pageYOffset)

      isRunning = false
    })
  }
})
  

mouse

Drag!
    var isDragging = false
var startPosition = null
var lastPosition = null
var requestId = null

var circle = document.getElementById('circle')

var translate = function(x, y) {
  circle.style.transform = 'translate3d(' + x + 'px,' + y + 'px,0)'
}

// この関数で描画する
var animate = function() {
  var x = lastPosition.x - startPosition.x
  var y = lastPosition.y - startPosition.y

  translate(x, y)

  requestId = window.requestAnimationFrame(animate)
}

// 最後にリセット
var leave = function() {
  isDragging = false
  translate(0, 0)

  // もう呼んでほしくないのでキャンセル
  if (requestId) {
    window.cancelAnimationFrame(requestId)
  }
}

// 円上でマウスが押されたらアニメーション開始
circle.addEventListener('mousedown', function(e) {
  isDragging = true
  startPosition = { x: e.clientX, y: e.clientY }
  lastPosition = { x: e.clientX, y: e.clientY }

  animate()
})

// 動いてるときは座標を更新して
circle.addEventListener('mousemove', function(e) {
  if (isDragging) {
    lastPosition = { x: e.clientX, y: e.clientY }
  }
})

// 離れたら手を引く
circle.addEventListener('mouseup', function(e) {
  leave()
})

circle.addEventListener('mouseleave', function(e) {
  leave()
})