Лучший способ Обработать отмену выполнения функции JavaScript

У меня есть три функции:

let timeVar;
let savedFunctionCode;

function startTimer(code) {
savedFunctionCode = code;
timeVar = setTimeout(savedFunctionCode, 2000);
}

function resumeTimer(intervalTime = 2000) {
setTimeout(savedFunctionCode, intervalTime);
}

function stopTimer() {
clearTimeout(timeVar);
}

Единственная цель этого — в основном способ приостановить и возобновить определенный код.

Теперь после создания экземпляра таймера (вызовом startTimer) есть возможность приостановить или возобновить выполнение кода.

Предполагаемое поведение приостановки и возобновления выполнения кода работает, ЕСЛИ методы stopTimer() и возобновитьTimer() вызываются с интервалом не менее двух секунд друг от друга.

Тем не менее, если вызовы restoreTimer() и stopTimer() в таком порядке вызываются менее чем через две секунды друг от друга, stopTimer() не сможет успешно остановить/приостановить ожидаемое выполнение возобновленияTimer().

Моя теория:

В состоянии паузы, когда вызывается submitTimer, код выполняется через две секунды. Однако, если вы быстро запустите stopTimer(), по сути нечего будет останавливать, потому что выполнение кода изSusumeTimer еще не началось. (менее двух секунд).

Таким образом, через две секунды метод возобновления работы с таймером () выполняет свой код, так как функция остановки (stopTimer) не влияет на него.

Вопрос: есть ли способ в JavaScript, чтобы когда я выполняю stopTimer(), он отменял все ожидающие выполнения кода. Итак, в этом случае я хотел бы, чтобы stopTimer() отменил выполнение кода возобновленияTimer(), которое произойдет через 2 секунды.

Пожалуйста, скажите, если это было неясно.

ПРИМЕР:

<html>
<body>
 <div id="media-holder">
<span id="play-button" onclick="resumeTimer();"></span>
<span id="pause-button" onclick="stopTimer();"></span>
</div>


<script>
let timeVar = setTimeout(execute, 2000); 

function resumeTimer(intervalTime = 2000) {
    setTimeout(execute, intervalTime);
}

function stopTimer() {
    clearTimeout(timeVar);
}

function foo() {
    for(let i = 0; i < 100; i++) {
        console.log("execute");
    }
}

</script>
 <html>

ЕСЛИ вы быстро нажмете кнопку воспроизведения и кнопку паузы, выполнение метода foo() все равно продолжится,


person bob9123    schedule 23.02.2018    source источник
comment
Не могли бы вы предоставить минимально воспроизводимый пример? Увидев, что проблема, которую вы описываете, действительно происходит, было бы чрезвычайно полезно для объяснения того, что не так и чего вы ожидаете вместо этого.   -  person Patrick Roberts    schedule 23.02.2018
comment
Я обновил свой вопрос.   -  person bob9123    schedule 23.02.2018
comment
Возможный дубликат Что такое версия sleep() для JavaScript?   -  person Daniel Netzer    schedule 23.02.2018


Ответы (1)


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

Однако вы можете создать прерываемую функцию, используя генератор:

function resumeTimer() {
  task.resume();
}

function stopTimer() {
  task.pause();
}

// the `*` means this is a generator function
function* foo() {
  let i = 0;

  while (true) {
    // every `yield` statement is a point
    // where control-flow is interrupted
    yield console.log(i++);
  }
}

class Task {
  constructor(iterator, ms = 16, autoplay = true) {
    this.step = this.step.bind(this);

    this.iterator = iterator;
    this.ms = ms;

    if (autoplay) {
      this.resume();
    }
  }

  step() {
    this.result = this.iterator.next((this.result || {}).value);
  }

  pause() {
    if (this.ref) {
      clearInterval(this.ref);
      this.ref = null;
    }
  }

  resume(ms = this.ms) {
    if (ms !== this.ms) {
      this.pause();
      this.ms = ms;
    }

    if (!this.ref) {
      this.step();
      this.ref = setInterval(this.step, this.ms);
    }
  }
}

let task = new Task(foo());
<button id="play-button" onclick="resumeTimer();">Play</button>
<button id="pause-button" onclick="stopTimer();">Pause</button>

Рекомендации

person Patrick Roberts    schedule 23.02.2018
comment
Спасибо, я увижу этот подход. Я изучал промисы, как они могут повлиять на это? - person bob9123; 23.02.2018
comment
@DylanWhite вы могли бы использовать async/await так же, как function* / yield, но написать метод для async/await, который может останавливать поток управления для функции на неопределенный срок, не так просто, и, если я не ошибаюсь, функция async с бесконечным циклом никогда не может быть помечен для сборки мусора, поскольку остальная часть его потока управления зависит от ожидающего обещания. - person Patrick Roberts; 23.02.2018
comment
Один быстрый вопрос, есть ли способ сделать так, чтобы он запускался мгновенно? Прямо сейчас он начинается после продолжительности переменной «мс». Есть ли способ заставить его начать сразу и после повторения последовательно с помощью «мс» - person bob9123; 23.02.2018
comment
Если бы я хотел изменить интервал времени выполнения во время его выполнения, было бы это так же просто, как вызов функции возобновления, но с аргументом, объявляющим время и передающим его аргументу setInterval? - person bob9123; 23.02.2018
comment
@DylanWhite, если у вас есть другие пожелания, задайте новый вопрос. - person Patrick Roberts; 23.02.2018