Наиболее эффективной реализацией JavaScript таймер обратного отсчета


У меня этот таймер работает уже(jsbin):

HTML-код:

  <input id="m" type="number" value="0" min="0" max="59"/>
  <input id="s" type="number" value="2" min="0" max="59"/>
  <input id="start" type="button" value="Start!" />
  <output>00:00</output>

На JavaScript:

var o = document.querySelector('output'),
m = document.querySelector('#m')
s = document.querySelector('#s'),
start = document.querySelector('#start');


start.addEventListener('click', function(){
    var mm = parseInt(m.value),
        ss = parseInt(s.value);
    timer = function(){
        if(mm>0){
            if(ss>0){
                ss--;
            }
            else{
                mm--;
                ss = 59;
            }
            setTimeout("timer()", 1000);
            o.value = (mm<10 ? '0' + mm : mm) + ":" + (ss<10 ? '0' + ss : ss);
        }
        else{
            if(ss>0){
                ss--;
                o.value = "00:" + (ss<10 ? '0' + ss : ss);
                setTimeout("timer()", 1000);
            }
        }
    }

    timer();
}, false);

Это кажется много кода для таймера. Можно ли реализовать это с меньше кода? Может быть, с петлями, дата объект или что-то еще?

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

Мой вопрос заключается в том, как оставить этот отсчет с ДЛЯ или во время?



5682
4
задан 22 октября 2011 в 07:10 Источник Поделиться
Комментарии
3 ответа

документ.querySelector("#идентификатор") - это просто дорогостоящая версия документа.метода getElementById("идентификатор"). документ.метода getElementById - это самый быстрый способ, чтобы выбрать элемент на странице (в smartasses вас: кроме документа.руководителя, документ.тела и т. д.)

документ.querySelector("отметить") тоже просто дорогую версию документа.метод getelementsbytagname("имя тега")[0]. Кстати, это второй самый быстрый способ получить элемент.

документ.querySelector и ее массивов версии полезны только для составных операторов, которые либо слишком долго или слишком трудно сделать с "обычным" дом методы. Можно утверждать, что если ваш HTML является составной и сложный, Вы делаете это неправильно, и они скорее всего правы.

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

Итак, что мы имеем до сих пор?

var output = document.getElementsByTagName("output")[0],
minutes = document.getElementById("m"),
seconds = document.getElementsById("m"),
start = document.getElementById("start");

Двигаемся дальше. Прослушиватель событий-это хорошо, теперь по поводу парсинга чисел...

Попробуйте этот кусок кода: parseInt("08"). Результат-0. Почему, спросите вы? Ну, если вы не пройти радикса в качестве второго параметра, parseInt будет приятно достаточно, чтобы догадаться, что вы имеете в виду. parseInt видит, что строка начинается с 0 и, конечно же, предполагает число в восьмеричной системе счисления! Почему бы ей не быть?

Точки: либо пройти радикса такой: parseInt(строка, 10) или использовать parseFloat, который будет всегда считать десятичное число. Как вам больше нравится, хотя я однажды слышал, что parseFloat быстрее, не знаю, правда ли это. Я лично предпочитаю parseFloat, без всякой видимой причины

Итак, мы получаем:

var mm = parseFloat(minutes.value),
ss = parseFloat(seconds.value);

Великолепный.

Эта линия:

timer = 

Содержит один из самых широко допустили ошибки в JavaScript. Это называется подразумеваемых глобальных.

В основном, когда вы опускаете ВАР заявлении, переменная определение списка добавляются в глобальный объект ( окно относится). Так:

function foo() { answer = 42; }
foo();
window.answer === 42;

Никогда не опускать ВАР заявлении. Даже если вы не хотите присвоить переменной к глобальному объекту, сделать это явно (окна.ответ = 42;). Лучше тогда пусть кто-то чешут затылок, пытаясь выяснить, как появилась волшебная переменные из, казалось бы, ниоткуда.

Кроме того еще одна вещь, ваш код нормально. Что это за вещь, спросите вы? функции setTimeout

Когда вы передаете строку в функции setTimeout, это то же самое как вызов метода eval. Он возвращает строку. Это медленно и плохо. Вместо этого, передать функцию к нему:

setTimeout(timer, 1000);

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

Теперь, кто-то может спросить: "каким образом я могу вызывать функции с параметрами?"

setTimeout(function() {
func(something, somethingElse);
}, 1000);
//or
setTimeout(func, 1000, something, somethingElse);

О ваш фактический код? это нормально. Это не самый лучший кусок кода, который я когда-либо, но это не хуже, а также. Это не слишком долго для таймера, поскольку все, что сделано, то уменьшится и звоню опять сама. Я бы переехал в < 10 проверяет свою функцию, но, возможно, это потому, что я безумен, а не так, что "свой путь" - это хуже.



Тл;др код содержит ошибки, но кроме этого, это прекрасно.

4
ответ дан 22 октября 2011 в 08:10 Источник Поделиться

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

Вот некоторые предложения:

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

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

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

document.querySelector('#start').addEventListener('click', function(){

var o = document.querySelector('output');
var t =
parseInt(document.querySelector('#m').value, 10) * 60 +
parseInt(document.querySelector('#s').value, 10);

var timer = function(){
if (t > 0) {
t--;
var m = Math.floor(t \ 60);
var s = t % 60;
o.value = (m < 10 ? '0' : '') + m + ":" + (s < 10 ? '0' : '') + s;
window.setTimeout(timer, 1000);
}
}

timer();
}, false);

Что касается стека вызовов: код не рекурсивный, поэтому он не будет строить вызовов в стеке вызовов. В Таймер Функция добавляет себя как событие, он не называет себя.

4
ответ дан 22 октября 2011 в 08:10 Источник Поделиться

Если вы используете секунд вместо мм:СС провести свое время, все будет проще.

Кроме того, вы можете инкапсулировать свои чтения и записи значений:

function readSeconds() {
return parseInt(m.value, 10) * 60 + parseInt(s.value, 10);
}

function output(seconds) {
var mm = seconds / 60, ss = seconds % 60;
o.value = (mm<10 ? '0' + mm : mm) + ":" + (ss<10 ? '0' + ss : ss);
}

Затем, вы можете легко написать свой метод start. Что-то вроде:

start.addEventListener('click', function(){
var seconds = readSeconds();
function timer(){
seconds--;
output(seconds);
setTimeout(timer, 1000);
}
timer();
}, false);

Очевидно, что это не все подробности, но немного инкапсуляция помогает совсем немного.

1
ответ дан 29 октября 2011 в 04:10 Источник Поделиться