#javascript #html #settimeout
#javascript #HTML #settimeout
Вопрос:
Вот часть кода, которая имеет значение:
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);
}
Обратите внимание, что это всего лишь фрагмент, который я хотел опробовать, прежде чем использовать подобный код в более крупном проекте. Это работает неправильно, изображение рисуется только один раз, то есть я вижу только последний нарисованный круг. Я загуглил это до смерти, но пока мне ничего не помогло.
Ответ №1:
То, что вы хотите использовать, это 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. Спасибо за подробный ответ. Это работает лучше, сайт ждет четыре секунды, чем рисует круг. Но то, что происходит после этого, странно. Функция drawcircle вызывается десять раз подряд с тем же значением для i, затем ожидает четыре секунды и повторяет процесс. Есть идеи относительно того, почему это происходит? Я впервые использую циклы в javascript наряду с canvas, поэтому точно определить ошибку довольно сложно.
2. Чтобы прояснить, что я хочу сделать, это: для каждого запуска цикла for вызывайте функцию drawcircle(…) и подождите четыре секунды. Таким образом, функция должна быть вызвана 10 раз, с i в диапазоне от 0 до 9, и процесс должен занять 40 секунд.
3. Я опубликую свой ответ в РЕДАКТИРОВАНИИ.
4. Это сработало как по волшебству 🙂 Это мой первый вопрос здесь, и я действительно удивлен оперативностью и качеством ответов. Спасибо, что, без сомнения, сделали меня постоянным посетителем здесь 🙂 И, конечно, спасибо другим, кто ответил.
5. Да, я заметил, но я не создавал учетную запись, поэтому я не мог проголосовать. Я сделал это сейчас, и я дам ответ с повышением, когда получу необходимую «репутацию». Я тоже поставил галочку. Спасибо за ссылку для получения дополнительной информации.
Ответ №2:
На самом деле есть пара вещей, которые приводят к неправильному поведению вашего кода, и все они связаны с тем, как написан ваш цикл. Первая проблема заключается в вызове setTimeout, главным образом в том, что вы не передаете ему объект function в качестве первого аргумента, и большинство людей исправили бы это, выполнив что-то вроде этого:
for (var i = 0; i < 10; i ) {
setTimeout(function() {
drawCircle(i, color2, color5);
}, 4000);
}
Это приведет к задержке setTimeout, как вы и ожидали, но в конечном итоге вызов drawCircle с 10 в качестве первого аргумента 10 раз, и это потому, что каждый вызов использует одну и ту же ссылку на переменную «i». Значение для i не извлекается до тех пор, пока не будет выполнен вызов … примерно через 4 секунды после завершения цикла, когда i уже 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.
Ответ №3:
Проблема здесь в том, что вы вызываете setTimeout несколько раз подряд, вместо того, чтобы вызывать его снова из обратного вызова. Попробуйте переместить вызов setTimeout
в конец drawCircle
функции, чтобы увидеть анимацию.