Я хочу рисовать на холсте с определенным интервалом, и setTimeout не работает - PullRequest
1 голос
/ 01 мая 2011

Вот часть кода, которая имеет значение:

function drawCircle(i, color1, color2) {
            var ctx = canvas.getContext("2d");
            if (i % 2 == 1) {
                ctx.fillStyle = color1;
            }
            else {
                ctx.fillStyle = color2;
            }
            ctx.beginPath();
            ctx.arc(110, 270, 10, 0, Math.PI * 2, true);
            ctx.closePath();
            ctx.fill();
        }
for (var i = 0; i < 10; i++) {
    setTimeout(drawCircle(i, color2, color5), 4000);
}

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

Ответы [ 3 ]

4 голосов
/ 01 мая 2011

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

Также я не думаю, что вы используете setTimeout правильно.Как вы уже написали, функция запускается перед тем, как передать что-либо на setTimeout / setInterval.Поэтому вы должны написать:

setInterval(function() {              // GOOD. An actual function is passed 
    drawCircle(...);                  // as the first argument.
}, 4000);

или:

setInterval('drawCircle(...)', 4000); // GOOD. the JS statement is supplied as 
                                      // a string and later on will be evaluated 
                                      // and executed with eval().

и НЕ :

setInterval(drawCircle(...), 4000);   // BAD! drawCircle() is fired, its result 
                                      // evaluated and passed on to setInterval 
                                      // that doesn't know what to do with it.

РЕДАКТИРОВАТЬ

У вас нет никаких процедур блокировки в JavaScript.Это однопоточный, управляемый событиями язык.Если вы называете что-то вроде setInterval, это сразу же получается.Только через 4 секунды или около того ваша функция обратного вызова будет вызвана.Тем не менее, в то же время JS будет заниматься различными вещами - например, реагировать на другие события, генерируемые пользователем.То, что вы хотите сделать, это вызвать setTimeout один раз, а затем внутри функции обратного вызова, непосредственно перед возвратом, снова вызвать ее с той же функцией и другим набором аргументов i.Что-то вроде этого:

function drawCircle(i, ...) {

    // ... do stuff ...

    if (i < 10) {                    // Check if the callback has been invoked 10 
                                     // times already.
        setTimeout(function() {      // Schedule the callback for execution
            drawCircle(i + 1, ...);  // again after anoter 4 seconds.
        }, 4000);
    }
}

setTimeout(function() {              // Invoke the callback the first time 
    drawCircle(1, ...);              // after first 4 seconds.
}, 4000);
1 голос
/ 01 мая 2011

На самом деле есть пара вещей, которые приводят к неправильному поведению вашего кода, и все они в том, как написан ваш цикл. Первая проблема - это вызов setTimeout, главным образом из-за того, что вы не передаете объект функции ему в качестве первого аргумента, и большинство людей исправят это, выполнив что-то вроде этого:

for (var i = 0; i < 10; i++) {
    setTimeout(function() {
        drawCircle(i, color2, color5);
    }, 4000);
}

Это вызовет задержку setTimeout, как вы и ожидали, но в конечном итоге вызовет drawCircle с 10 в качестве первого аргумента 10 раз, и это потому, что каждый вызов использует одну и ту же ссылку на переменную "i". Значение i не извлекается до тех пор, пока не будет выполнен вызов ... через 4 секунды после завершения цикла, когда мне уже 10.

Чтобы обойти это, вам нужна еще одна функция:

function getDrawer(i, color2, color5) {
    return function() {
        drawCircle(i, color2, color5);
    }
}

for (var i = 0; i < 10; i++) {
    setTimeout(getDrawer(i, color2, color5), 4000);
}

Функция getDrawer (ужасное имя, пожалуйста, не используйте ее) вызывается немедленно, поэтому к значению i обращаются сразу и запоминает анонимная функция, которую возвращает getDrawer. Эта анонимная функция будет вызываться setTimeout.

1 голос
/ 01 мая 2011

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

...