Как запретить функции возвращать новый результат до истечения x секунд и возвращать предыдущий результат, если он вызван слишком рано

#javascript

#javascript

Вопрос:

Создание функции onceEvery() , которая позволяет вызывать функцию только один раз каждые x миллисекунд. Первый результат может быть возвращен, но функция не останавливает его отзыв до завершения времени перезарядки, возвращая вместо этого предыдущий результат. Заранее спасибо!

 onceEvery =  function (func, wait) {
//return function then can only return every * seconds
  let cooldown = false;
  let resu<
  let previous;
  //if called again while cooldown = true, return previous result
  if (!cooldown) {
    result = func;
    previous = resu<
    beginCoolDown();
    return resu<
  } else {
    return previous;
  }
  
  function beginCoolDown () {
    cooldown  = true;
    setTimeout (function () {
      cooldown = false;
    }, wait);
   }
  } 

Комментарии:

1. в чем проблема с кодом? у вас тоже есть пример?

2. Я думаю, что этот вопрос немного сбивает с толку. Не могли бы вы добавить больше деталей, таких как вызывающий код, и каковы выходные данные, и каковы ожидаемые выходные данные вместо этого?

3. Конечно, я забыл добавить переменные (которые я добавил сейчас). В принципе, функция onceEvery() должна принимать две переменные — func (функция) и wait (время в мс, прежде чем функция может быть вызвана снова). После вызова функции она должна вернуть результат, но затем не может быть вызвана в течение секунд ожидания (если она вызывается в течение этого времени, она возвращает результат предыдущего вызова). Я надеюсь, что это более понятно

Ответ №1:

Вы делаете это, отслеживая последний предоставленный вами результат и время его последнего предоставления вне функции, а затем используя его при вызове функции, чтобы решить, следует ли обновлять эту информацию:

 const minInterval = 5000;       // 5 seconds (for example)
let lastResult = null;          // Last result provided
let nextAvailable = Date.now(); // When the next can be provided
function onceEvery() {
    const now = Date.now();
    if (now < nextAvailable) {
        return lastResu<
    }
    lastResult = /*...calculate result...*/;
    nextAvailable = now   minInterval;
    return lastResu<
}
 

Живой пример:

 const minInterval = 5000;       // 5 seconds (for example)
let lastResult = null;          // Last result provided
let nextAvailable = Date.now(); // When the next can be provided
function onceEvery() {
    const now = Date.now();
    if (now < nextAvailable) {
        console.log(Date.now(), "Too soon, returning last value:", lastResult);
        return lastResu<
    }
    lastResult = (lastResult || 0)   1;
    nextAvailable = now   minInterval;
    console.log(Date.now(), "Calculated new value:", lastResult);
    return lastResu<
}

// Call it every second or so
setInterval(onceEvery, 1000); 

Ответ №2:

Вы можете использовать концепцию замыканий JavaScript. Возвращает обернутую функцию, которая выполняется только после wait периода ожидания.

Для этого поддерживайте флаг isCalled во внешней функции, который изначально false предназначен для того, чтобы функция могла быть вызвана немедленно.

После вызова значение isCalled устанавливается true таким образом, что при следующих вызовах функция должна ждать, пока таймер не выполнит и не сбросит его на false :

 function onceEvery(func, wait) {
  let isCalled = false;
  let resu<
  return () => {
    //if not called call the func
    if (!isCalled) {
      result = func();
      //set to true
      isCalled = true;
      setTimeout(() => {
        //reset after waiting wait period
        isCalled = false;
      }, wait);
    }
    //return computed value
    //returns old value until new value is computed
    return resu<
  }
}

let func = onceEvery(() => Date.now(), 2000);

setInterval(() => {
  console.log(func());
}, 400) 

Комментарии:

1. Большое спасибо за четкое объяснение и код — теперь он работает! Не могли бы вы объяснить, почему «let isCalled = false» в верхней части функции не превысит время ожидания, если функция будет отозвана? Надеюсь, это имело смысл..

2. Поскольку onceEvery вызывается только один раз , после вызова он возвращает внутреннюю функцию, которая является фактической функцией, вызываемой несколько раз. Эта внутренняя функция формирует замыкание, которое имеет доступ к состоянию переменной isCalled внешней функции, поэтому каждый раз, когда вы вызываете внутреннюю функцию, она просто использует и устанавливает переменную isCalled, но никогда не объявляет ее.

Ответ №3:

Вы должны определить функцию beginCoolDown() вне onceEvery() и переместить определение времени восстановления за пределы функции. Это будет выглядеть так:

 let cooldown = false
function beginCoolDown() {
...
}
function onceEvery() {
...
}