Таймер обратного отсчета JavaScript с возвращаемым значением после каждого интервала

Я пытаюсь написать таймер обратного отсчета, который возвращает текущее значение обратного отсчета из функции. Пока мне удалось написать функцию обратного отсчета. Он ведет обратный отсчет, но функция возвращает неопределенное значение. Как я могу изменить код, чтобы вернуть значение обратного отсчета?

const startTimer = (duration, onlySeconds) => {
  var timer = duration,
    minutes,
    seconds;
  const interval = setInterval(function () {
    minutes = parseInt(timer / 60, 10);
    seconds = parseInt(timer % 60, 10);

    minutes = minutes < 10 ? "0" + minutes : minutes;
    seconds = seconds < 10 ? "0" + seconds : seconds;

    if (timer-- === 0) {
      clearInterval(interval)
    }
    console.info('seconds', seconds)
    return !onlySeconds ? minutes + ":" + seconds : seconds;
  }, 1000);
};

console.info('You will be logged out in ', startTimer(3, true))

Вы не знаете, правда. Вы делаете то же самое, что и с первым console.info(), но вместо этого обновляете страницу.

Ouroborus 15.12.2020 05:00

вы ожидаете, что он вернется несколько раз?

Paul Rooney 15.12.2020 06:58

@ПолРуни. Да, я ожидал, что он будет возвращать данные каждую секунду.

Kiran Dash 15.12.2020 07:09

Возврат работает не так. Он просто возвращается один раз, а затем завершается. Вам нужно использовать асинхронные механизмы, такие как обратные вызовы или промисы. Ответы, предоставленные до сих пор, кажутся довольно хорошими.

Paul Rooney 15.12.2020 07:14
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
4
1 047
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

const startTimer = (duration, onlySeconds, logger) => {
  var timer = duration,
    minutes,
    seconds;
  const interval = setInterval(function () {
    minutes = parseInt(timer / 60, 10);
    seconds = parseInt(timer % 60, 10);

    minutes = minutes < 10 ? "0" + minutes : minutes;
    seconds = seconds < 10 ? "0" + seconds : seconds;

    if (timer-- === 0) {
      clearInterval(interval)
    }
    
    const time = !onlySeconds ? minutes + ":" + seconds : seconds;
    logger(time);
  }, 1000);
};

const logger = (time) => {
  console.info('You will be logged out in ' + time);
}

startTimer(300, false, logger)

это намного проще и прямо в точку

const startTimer = (duration, onlySeconds) => {
  var timer = duration,
    minutes,
    seconds; 
  const interval = setInterval(function () {
    minutes = parseInt(timer / 60, 10);
    seconds = parseInt(timer % 60, 10);

    minutes = minutes < 10 ? "0" + minutes : minutes;
    seconds = seconds < 10 ? "0" + seconds : seconds;
    
    if (timer-- === 0) {
      clearInterval(interval)
    }
    console.info('You will be logged out in '+ (!onlySeconds ? minutes + ":" + seconds : seconds));
  }, 1000);
};
startTimer(3, true);

Я думаю, что другая стратегия может быть в порядке.

class Countdown {
  constructor() {
    this._init();
  }
  _init(restart=false) {
    this.target = undefined;
    this.running = false;
    this.terminate = false;
    if (!restart) {
      this.ms = undefined;
      this.tick = [];
      this.done = [];
    }
  }
  // Set a callback that is called every second. `fn(remaining)`
  ontick(fn) {
    this.tick.push(fn);
  }
  // Set a callback that is called when the countdown ends. `fn()`
  ondone(fn) {
    this.done.push(fn);
  }
  // Start countdown with duration in milliseconds
  start(ms) {
    const now = performance.now();
    if (this.running) throw new Exception('Countdown already running.');
    this.running = true;
    this.ms = ms;
    this.target = now + ms;
    this.update = () => {
      const now = performance.now();
      if (this.terminate) {
        this._init();
        return;
      }
      const remaining = this.target - now;
      if (remaining > 100) {
        setTimeout(this.update, remaining % 1000);
        this.tick.forEach(fn => fn(remaining));
      }
      else {
        this.done.forEach(fn => fn());
        this._init();
      }
    };
    setTimeout(this.update, this.target % 1000);
  }
  // Restart a running countdown. Optionally provide a new duration.
  restart(ms=this.ms) {
    const now = performance.now();
    if (!this.running) throw new Exception('Countdown not running.');
    this.ms = ms;
    this.target = now + ms;
  }
  // Stop a running countdown.
  stop() {
    if (!this.running) throw new Exception('Countdown not running.');
    this.terminate = true;
  }
}

Тогда вы будете использовать его следующим образом:

const countdown = new Countdown();
countdown.ontick(remaining => {
  console.info('Remaining:', remaining, 'ms');
});
countdown.ondone(() => {
  console.info('Countdown completed.');
});
countdown.start(15*60*1000); // 15 minutes

Если вы хотите перезапустить текущий обратный отсчет:

countdown.restart(5*60*1000); // Update target duration to 5 minutes and restart
countdown.restart(); // Use previous duration and restart

Если вы хотите отменить обратный отсчет:

countdown.stop();

Другие вопросы по теме