У меня есть этот script:
for (var i = 1; i <= 2; i++) {
setTimeout(function() { alert(i) }, 100);
}
Но 3
предупреждается обоим раза, а не 1
, а затем 2
.
Есть ли способ передать i
, не записывая функцию в виде строки?
У меня есть этот script:
for (var i = 1; i <= 2; i++) {
setTimeout(function() { alert(i) }, 100);
}
Но 3
предупреждается обоим раза, а не 1
, а затем 2
.
Есть ли способ передать i
, не записывая функцию в виде строки?
Вы должны организовать отдельную копию "i" для каждой функции тайм-аута.
function doSetTimeout(i) {
setTimeout(function() { alert(i); }, 100);
}
for (var i = 1; i <= 2; ++i)
doSetTimeout(i);
Если вы не сделаете что-то подобное (и есть другие варианты этой же идеи), то каждая из функций-обработчиков таймера будет иметь одну и ту же переменную "i". Когда цикл закончится, какое значение у "i"? Это 3! Используя посредническую функцию, создается копия значения переменной. Поскольку обработчик тайм-аута создается в контексте этой копии, у него есть свой собственный "i" для использования.
редактировать - со временем было несколько комментариев, в которых была очевидна некоторая путаница в связи с тем фактом, что установка нескольких тайм-аутов приводит к тому, что обработчики запускаются одновременно. Важно понимать, что процесс установки таймера - вызовы setTimeout()
- практически не занимают время. То есть, говоря системе "Пожалуйста, вызовите эту функцию через 1000 миллисекунд", вы вернетесь почти немедленно, так как процесс установки запроса на тайм-аут в очереди таймера очень быстрый.
Таким образом, если выполняется последовательность запросов времени ожидания, как это имеет место в коде в OP и в моем ответе, и значение задержки времени одинаково для каждого, то после того, как это количество времени истекло, все обработчики таймера будет вызываться один за другим в быстрой последовательности.
Если вам нужно, чтобы обработчики вызывались с интервалами, вы можете либо использовать setInterval()
, который вызывается точно так же, как setTimeout()
но который будет срабатывать более одного раза после повторных задержек запрошенной суммы, или вместо этого вы можете установить время ожидания и умножьте значение времени на ваш счетчик итераций. То есть, чтобы изменить мой пример кода:
function doScaledTimeout(i) {
setTimeout(function() {
alert(i);
}, i * 5000);
}
(При тайм-ауте в 100
миллисекунд эффект не будет очень очевидным, поэтому я увеличил число до 5000.) Значение i
умножается на значение базовой задержки, поэтому вызов 5 раз в цикле приведет к задержкам 5 секунд, 10 секунд, 15 секунд, 20 секунд и 25 секунд.
Обновить
Здесь, в 2018 году, существует более простая альтернатива. С новой возможностью объявлять переменные в областях, более узких, чем функции, оригинальный код будет работать, если так изменить:
for (let i = 1; i <= 2; i++) {
setTimeout(function() { alert(i) }, 100);
}
Объявление let
, в отличие от var
, само по себе приведет к тому, что для каждой итерации цикла будет свой i
.
Вы можете использовать функциональное выражение с немедленным вызовом (IIFE), чтобы создать замыкание вокруг setTimeout
:
for (var i = 1; i <= 3; i++) {
(function(index) {
setTimeout(function() { alert(index); }, i * 1000);
})(i);
}
Аргумент функции setTimeout
закрывает переменную цикла. Цикл заканчивается до первого таймаута и отображает текущее значение i
, которое равно 3
.
Поскольку переменные JavaScript имеют только область функций, решение должно передать переменную цикла функции, задающей тайм-аут. Вы можете объявить и вызвать такую функцию следующим образом:
for (var i = 1; i <= 2; i++) {
(function (x) {
setTimeout(function () { alert(x); }, 100);
})(i);
}
Это потому, что !
Решение, объявляющее единую область для каждой итерации, используя выполненную самофункцию (анонимный или лучше IIFE) и имеющий копию i в нем, например:
for (var i = 1; i <= 2; i++) {
(function(){
var j = i;
setTimeout(function() { console.log(j) }, 100);
})();
}
чище было бы
for (var i = 1; i <= 2; i++) {
(function(i){
setTimeout(function() { console.log(i) }, 100);
})(i);
}
Использование iFE (самозапускаемой функции) внутри каждой итерации создало новую область для каждой итерации, которая дала нам функцию тайм-аута, которая вызывает обратную функцию для закрытия новой области для каждой итерации, которая имела переменную с правильной переменной, итерации в нем для доступа.
Вы можете использовать дополнительные аргументы для setTimeout для передачи параметров функции обратного вызова.
for (var i = 1; i <= 2; i++) {
setTimeout(function(j) { alert(j) }, 100, i);
}
Примечание. Это не работает в IE9 и ниже браузеров.
ANSWER
Я использую его для анимации для добавления предметов в корзину. Значок корзины плавает в области корзины с кнопки "добавить" продукта при нажатии:
function addCartItem(opts) {
for (var i=0; i<opts.qty; i++) {
setTimeout(function() {
console.log('ADDED ONE!');
}, 1000*i);
}
};
ПРИМЕЧАНИЕ. Продолжительность в единицах времени n epocs.
Итак, начиная с момента клика, epoc анимации (из каждой анимации) является произведением каждого односекундного блока, умноженного на количество элементов.
epoc: https://en.wikipedia.org/wiki/Epoch_ (reference_date)
Надеюсь, это поможет!
Вы можете использовать метод bind
for (var i = 1, j = 1; i <= 3; i++, j++) {
setTimeout(function() {
alert(this);
}.bind(i), j * 100);
}
Ну, другое рабочее решение, основанное на ответе Коди, но немного более общее может быть примерно так:
function timedAlert(msg, timing){
setTimeout(function(){
alert(msg);
}, timing);
}
function yourFunction(time, counter){
for (var i = 1; i <= counter; i++) {
var msg = i, timing = i * time * 1000; //this is in seconds
timedAlert (msg, timing);
};
}
yourFunction(timeInSeconds, counter); // well here are the values of your choice.
У меня была такая же проблема, как только я решил это.
Предположим, что я хочу 12 задержек с интервалом в 2 секунды
function animate(i){
myVar=setTimeout(function(){
alert(i);
if(i==12){
clearTimeout(myVar);
return;
}
animate(i+1)
},2000)
}
var i=1; //i is the start point 1 to 12 that is
animate(i); //1,2,3,4..12 will be alerted with 2 sec delay
настоящее решение здесь, но вам нужно быть знакомым с языком программирования PHP. вы должны смешивать заказы PHP и JAVASCRIPT, чтобы достичь своей цели.
обратите внимание на это:
<?php
for($i=1;$i<=3;$i++){
echo "<script language='javascript' >
setTimeout(function(){alert('".$i."');},3000);
</script>";
}
?>
Он точно делает то, что вы хотите, но будьте осторожны с тем, как сделать рационализацию между Переменные PHP и JAVASCRIPT.