clearTimeout не работает - пробовал много вариантов

У меня проблема с функцией clearTimeout. Оба условия работают, но тайм-аут отказывается очищаться ...... приветствуется любая помощь. Время 300 миллисекунд = params.speed.

**ПРИМЕЧАНИЕ. Этот метод полностью функционален и работает. Единственная проблема, с которой я столкнулся, это очистка setTimeout. Это создает ошибку, когда к новым тостерам без тайм-аута применяется старый setTimeout.

Это означает, что если я нажму кнопку без тайм-аута в течение 3 секунд после нажатия кнопки тайм-аута, старый setTimeout все еще будет применяться к следующему тостеру.

        // Beginning of function - line below contains the options for the 
        // toaster method:
        // Invoke via - onclick(e, {text: 'This is an alert with a TIMER', 
        // timer:true, speed: 3500, color: 'dark'})

        toaster: function(e, params = {}) {

            // Set defaults for params.object options
            var setDefaults = function () {
                if (e == null) {
                    e = this.event;
                };
                if (params.speed == null) {
                    params.speed = 3500;
                };
                if (params.timer == null) {
                    params.timer = false;
                };
                if (params.color == null) {
                    params.color = 'light';
                };
                if (params.text == null) {
                    params.text = 'This is a default warning'
                };
            }();

          //Apply timer function
          timerOn(params.speed); // params.speed = 4500
          var timing; // Variable set outside of the timerOn() function

          function timerOn () {

                if (params.timer) {
                    timing = setTimeout(function(){
                        el[0].classList.remove('show-toaster');
                        console.log('happening');
                    }, params.speed);  
                } else {
                    clearTimeout(timing);
                    console.log('just cleared timing variable');
                } 

            } // timerOn ends

person bubbaShrimp    schedule 22.03.2018    source источник
comment
Опубликуйте минимальный, полный и проверяемый пример.   -  person Ele    schedule 23.03.2018
comment
Как я могу сделать его более минимальным и полным?   -  person bubbaShrimp    schedule 23.03.2018
comment
Когда вы вызываете timerOn дважды с установленным params.timer, вы теряете ссылку на первый таймер. Это может быть проблемой   -  person Jonas Wilms    schedule 23.03.2018
comment
Вы меняете timing где-нибудь еще? Возможно, у вас есть другая функция, которая перезаписывает эту переменную.   -  person Paul    schedule 23.03.2018
comment
Спасибо @JonasW. - просто любопытно, где я дважды вызываю timerOn? Вы имеете в виду условный аргумент. RE: params.timer представляет только целочисленное значение 3000.   -  person bubbaShrimp    schedule 23.03.2018
comment
Нет, @Paulpro - спасибо за предложение.   -  person bubbaShrimp    schedule 23.03.2018
comment
Если params.timer всегда будет 3000, в какой момент вы собираетесь вызывать clearTimeout?   -  person Keith    schedule 23.03.2018
comment
Если params.timer равно 3000 каждый раз, когда вы вызываете timerOn, вы будете только добавлять таймеры и никогда не будете их удалять. 3000 соответствует действительности, поэтому блок if будет выполняться всегда, а блок else никогда.   -  person Paul    schedule 23.03.2018
comment
Привет @Paulpro, хорошая идея, но я тестировал с консолями, и обе стороны условного выражения работают должным образом. params.timer — это аргумент, содержащий функцию.   -  person bubbaShrimp    schedule 23.03.2018
comment
@bubbaShrimp Но вы сказали, что params.timer представляет в комментарии только целочисленное значение 3000. Является ли все остальное ложным, например 0, false или undefined?   -  person Paul    schedule 23.03.2018
comment
Таймер параметров @Paulpro является либо целым числом, либо значением false   -  person bubbaShrimp    schedule 23.03.2018
comment
Итак, когда вы устанавливаете его в false после запуска... How could I make it more minimal and complete? Преобразование вашего кода в фрагмент действительно поможет здесь. ClearTimeout, безусловно, работает, так что здесь ошибка где-то еще.   -  person Keith    schedule 23.03.2018
comment
@bubbaShrimp Тогда, боюсь, Эле права. Вам нужно сделать свой пример более полным, опубликовав достаточно кода, чтобы воспроизвести проблему, чтобы было достаточно контекста, чтобы кто-то мог вам помочь. Разместите только достаточно кода, чтобы воспроизвести его, не больше, чтобы вы также не потеряли минимальный аспект MCVE. Сократив свой код до объема, необходимого для воспроизведения проблемы, вы, вероятно, в конечном итоге сами выясните причину ошибки, а затем сможете опубликовать ответ на свой вопрос и принять его.   -  person Paul    schedule 23.03.2018
comment
Есть разные кнопки, вызывающие одну и ту же функцию. Один передает параметр 3000 миллисекунд = param.timer. Кнопка удаления без учета времени сообщает false = param.timer. С логикой все в порядке, но таймаут не сбрасывается   -  person bubbaShrimp    schedule 23.03.2018
comment
@Paulpro Спасибо. Да, правда, пытался избежать слишком большого количества кода, постараюсь добавить больше контекста.   -  person bubbaShrimp    schedule 23.03.2018
comment
The logic is fine Очевидно, что нет, иначе у вас не было бы проблем. :)   -  person Keith    schedule 23.03.2018
comment
Логика @Keith означает, что условное выражение работает как надо, хотя хорошая шутка   -  person bubbaShrimp    schedule 23.03.2018
comment
timerOn(params.speed); Ваша функция timerOn не принимает аргументов, params.speed не имеет смысла.   -  person Keith    schedule 23.03.2018
comment
Ваш timing var находится внутри замыкания, он никогда не будет равен тому же таймеру, что и другой созданный вами. Таким образом, вы не сможете очистить этот таймер. это должно быть вне закрытия.   -  person Keith    schedule 23.03.2018
comment
@Кит, спасибо за идеи. TimingOn() имеет аргумент 4500. Возможно, это закрытие, но у меня есть время как переменная вне функции?   -  person bubbaShrimp    schedule 23.03.2018
comment
Все еще запутался здесь, в какой-то момент вы вызываете timerOn, когда params.timer ложно. Нигде в коде, который вы разместили, вы не делаете этого.   -  person Keith    schedule 23.03.2018
comment
Вы пытаетесь очистить тайм-аут, используя toaster с params timer = false, если это так, это не сработает из-за части закрытия, которую я упомянул. Экземпляр timer var будет новым со значением undefined..   -  person Keith    schedule 23.03.2018
comment
Привет, Кейт. См. вызов через комментарий в верхней части экрана. Параметры содержат true для params.timer. Хотя спасибо за идею   -  person bubbaShrimp    schedule 23.03.2018
comment
Вызовите что?, как, когда.. Если ваша вторая кнопка вызывает toater с params timer = false, это не сработает. Это связано с тем, что var timer является новой переменной каждый раз, когда вы вызываете toater, поэтому выполнение clearTimeout ничего не даст.   -  person Keith    schedule 23.03.2018
comment
@Keith, хорошо, я с тобой. Это потому, что таймер var - это новый var каждый раз, когда вы вызываете тостер........ Итак, как мне это исправить?   -  person bubbaShrimp    schedule 23.03.2018
comment
Привет, @Keith, params.timer = false должен очищать переменные «время» setTimeOut? Это то, для чего предназначен if/else, и переменная 'timing' также объявляется в более высокой области видимости над функцией TimingOn. Я не думаю, что свойство таймера имеет какое-либо отношение к этой проблеме.   -  person bubbaShrimp    schedule 23.03.2018
comment
higher scope above the timingOn Но это должно быть более масштабно, чем ваша функция toaster.. Я опубликую простой пример того, что вы делаете, надеюсь, понимание этого поможет вам понять вашу проблему.   -  person Keith    schedule 23.03.2018
comment
Фантастика, спасибо за это, все еще не знаю, как еще один шаг вверх по лестнице масштаба решит эту проблему. Буду рад увидеть это, если это сработает ;)   -  person bubbaShrimp    schedule 23.03.2018


Ответы (2)


То, что мы здесь имеем, я считаю проблемой масштаба.

Допустим, у нас есть функция test, и когда мы вызываем ее с помощью true, мы сохраняем слово hello в переменную с именем x. Если мы затем снова вызовем указанную функцию с ложным значением, мы хотим, чтобы в console.log значение x, надеюсь, было словом hello.

Мы могли бы создать такую ​​функцию->

function test(b) { var x; if (b) x = "hello"; else console.log(x); }
test(true); 
test(false);  //prints undefined

Теперь вышеизложенное, основанное на том, что сказал ОП, - это то, что он делает с функцией тостера. Проблема в том, что приведенное выше приведет к печати undefined

Так как же нам исправить,. Все, что нам нужно сделать, это переместить объявление var x так, чтобы оно покрывало функцию test, тогда область var x станет глобальной для этого экземпляра теста. IOW: каждый раз, когда мы вызываем test, мы хотим, чтобы он видел один и тот же экземпляр x..

Итак, вот исправленная версия.

var x; function test(b) { if (b) x = "hello"; else console.log(x); }  
test(true); 
test(false);  //prints hello

Это, как и ожидалось, напечатает слово hello..

Теперь, если вы думаете, что функция test была функцией toaster, а var x была переменной timer, вы можете увидеть, что переменная timer окажется неопределенной при следующем вызове toaster.

person Keith    schedule 23.03.2018
comment
Это определенно проблема. - person Paul; 23.03.2018
comment
Круто, спасибо за информацию @Keith. Итак, поскольку переменная «time» из метода тостера не находится в локальной области timerOn(), что мне делать? - person bubbaShrimp; 23.03.2018
comment
Я переместил переменную 'time' в более высокий контекст, чем метод тостера (который содержал много внутренних функций). Как сказал Кит, более широкий охват решил проблему. Переменная «время» должна была перейти в более высокую область действия из-за ее изменяющегося значения, иногда содержащего setTimeout. Также объем выше, чем окружающие внутренние функции. Определенно новый для меня. Пример кода в проблеме показал, что переменная «время» была поднята до более высокого уровня… хотя и недостаточно высокого. Спасибо @Keith и всем остальным за вашу помощь. - person bubbaShrimp; 23.03.2018
comment
@bubbaShrimp Просто чтобы уточнить ваше понимание. Проблема заключалась в том, что timing было объявлено внутри toaster, поэтому каждый вызов toaster создавал новую переменную с именем timing. На самом деле каждый вызов toaster также создает новую функцию с именем timerOn. Каждый раз, когда вы вызывали timerOn, вы вызывали другую вновь созданную функцию, имеющую собственную цепочку областей видимости (включая собственную переменную timing), отдельную от любой другой идентично выглядящей функции с именем timerOn, которая была создана предыдущими вызовами toaster. - person Paul; 23.03.2018
comment
@bubbaShrimp Перемещение объявления timing за пределы toaster означает, что каждый вызов toaster больше не создает новую переменную timing. Скорее, все они имеют более высокий масштаб timing. Таким образом, последующие вызовы имеют доступ к переменной timing, установленной предыдущим вызовом, и могут очистить интервал. - person Paul; 23.03.2018
comment
@bubbaShrimp По-прежнему создается новая копия функции timerOn каждый раз, когда вызывается toaster, поскольку объявление этой функции все еще находится внутри toaster, но каждая функция, называемая timerOn, должна искать дальше по цепочке областей видимости за пределами toaster, чтобы найти timing сейчас, поэтому все они имеют один и тот же timing. - person Paul; 23.03.2018

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

var timing;
var params = {
  timer: true,
  speed: 3000
};

function timerToggle() {
  clearTimeout(timing);
  if (params.timer) {
    timing = setTimeout(function() {
      alert("timer works");
    }, params.speed);
  }
}    

timerToggle();

$("button").on("click", function() {
  params.timer = false;
  timerToggle();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>click me or wait 3 sec</button>

person Profesor08    schedule 22.03.2018
comment
Это хорошо, но тоже пробовали. Я разместил cleartimeout там, где вы предлагаете. А также использовали условный вариант с одним вариантом, например, ваш код. По-прежнему не исправляет, что setTimeout не очищается. - person bubbaShrimp; 23.03.2018
comment
clearTimeout(timing); звонит каждый раз, когда вы звоните timerToggle. И он очищает тайм-аут каждый раз. Я думаю, что вы вызываете свою функцию слишком поздно. Увеличьте скорость в 10 раз, чтобы иметь время подумать, где ваш код неверен. - person Profesor08; 23.03.2018
comment
@bubbaShrimp Также это рабочий фрагмент, почему он не работает так, как вы ожидаете, .. Если вы щелкнете приведенный выше фрагмент кода запуска и подождите 3 секунды, вы получите диалоговое окно, но если вместо этого вы нажмете click me or wait 3 sec, диалоговое окно не появится, доказывая, что clearTimeout сделал то, что было сказано на банке. - person Keith; 23.03.2018
comment
Конечно, @Keith, я хорошенько посмотрю. clearTimeout никогда не был проблемой раньше. В связи с этим у меня возникли проблемы. Интересно, связано ли это с gulp, dom memory или даже прослушивателями событий, которые я использую? - person bubbaShrimp; 23.03.2018