Заметки за март 2014 года

Однократный вызов функции с таймаутом

Бывает нужно подписаться на какое-то событие, но нет уверенности, что оно вообще может наступить. Можно условиться о неком интервале, в течение которого мы ожидаем это событие.

/**
 * @param {Function} fn function which needs to be called only once
 * @param {Number} timeout for external call
 * @param {Object} [context]
 * @returns {Function}
 */
function withTimeout(fn, timeout, context) {
  var timerId, state = true;

  function cb() {
    if (timerId) {
      clearTimeout(timerId);
      timerId = null;
    }
    if (state) {
      state = false;
      fn.apply(context || window, arguments);
    }
  }

  timerId = setTimeout(cb, timeout);

  return cb;
}

С использованием промисов код получился бы чуть короче, но потребовал бы внешнюю зависимость в виде jQuery или другой библиотеки, реализующей промисы.

Комментарии к заметке: 1

Вызов функции «чуть позже»

Мы уже привыкли пользоваться setTimeout(fn, 0), чтобы запланировать вызов некой функции и продолжить выполнение текущего кода. Мы ожидаем, что запланированный вызов произойдёт максимально быстро на сколько это возможно. Однако у всех JavaScript движков есть ограничение — 4 миллисекунды. Побороть это ограничение можно, если пользоваться requestAnimationFrame или setImmediate.

/**
 * Runs the callback at the next available opportunity.
 * @see https://developer.mozilla.org/en-US/docs/Web/API/window.setImmediate
 */
var setImmediate = function(callback) {
  return (
    window.setImmediate ||
    window.requestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.setTimeout
  )(callback, 0);
};

/**
 * Clears a callback previously registered with `setImmediate`.
 * @param {id} id The identifier of the callback to abort
 */
var clearImmediate = function(id) {
  return (window.clearImmediate ||
    window.cancelAnimationFrame ||
    window.webkitCancelAnimationFrame ||
    window.mozCancelAnimationFrame ||
    window.clearTimeout)(id);
};

Метод setImmediate объекта window был реализован в IE10 и Node.js 10+, но встретил сопротивление со стороны разработчиков Firefox и WebKit из-за неясности спецификации.

Комментарии к заметке: 4