setTimeout и массив каждый
Я смущен использованием setTimeout и каждого итератора. Как я могу переписать следующее, чтобы консоль выводила каждое имя после задержки в 5 секунд? В настоящее время код ниже выводит все имена сразу после 5 секунд. Я хотел бы:
1) подождите 5 секунд, затем распечатайте kevin
2) подождите 5 секунд, затем распечатайте mike
3) подождите 5 секунд, затем распечатайте sally
var ary = ['kevin', 'mike', 'sally'];
_(ary).each(function(person){
setTimeout(function(){
console.log(person);
}, 5000);
});
5 ответов
вы можете создать переменную с именем offset
это заставляет таймер ждать еще 5 секунд для каждого человека в массиве, например:
var ary = ['kevin', 'mike', 'sally'];
var offset = 0;
_(ary).each(function(person){
setTimeout(function(){
console.log(person);
}, 5000 + offset);
offset += 5000;
});
вы могли бы сделать
var ary = ['kevin', 'mike', 'sally'];
_(ary).each(function(person, index){
setTimeout(function(){
console.log(person);
}, index * 5000);
});
без увеличения timeout
значение, вы инициализируете все setTimeouts
С точно таким же значением (thats, почему вы видите то, что вы видите).
у вас есть три основных варианта:
-
Для Петли +
setTimeout
... инициализируйте всех немедленно, но пошатните время начала на основе позиции индекса, чтобы они не все шли одновременно. -
setTimeout
+ условный рекурсии
... зайдите в каждый n секунд - и я скажу вам, если вам нужно сделать другой -
setInterval
+ условноеclearInterval
... продолжайте работать каждый n секунды-пока я не скажу тебе остановиться
вот каждый из тех, кто облекся с рабочим примером:
1. Для Петли + setTimeout
пара заметок об этом. Это похоже на запуск эстафеты и раздачу инструкций заранее каждому бегуну, чтобы начать точно в 5: 00 и 5:02 и 5: 04, независимо от того, закончил ли человек за ними долгое время давно или еще не приехал.
кроме того, вы не можете использовать обычный for i=0 loop
, поскольку оператор for не определяет область новой функции. Таким образом, значения объектов, установленные в каждом цикле for, будут применяться на итерациях. К моменту вызова setTimeout будет использоваться только самое последнее значение. Поэтому нам нужно закрытие, чтобы сохранить значение в каждом цикле. Я использовал Array.prototype.forEach()
, но если вы хотите использовать реализации forEach в jQuery или подчеркивании, это будет работать тоже.
function ArrayPlusDelay(array, delegate, delay) {
// initialize all calls right away
array.forEach(function (el, i) {
setTimeout(function() {
// each loop, call passed in function
delegate( array[i]);
// stagger the timeout for each loop by the index
}, i * delay);
})
}
// call like this
ArrayPlusDelay(['a','b','c'], function(obj) {console.log(obj)},1000)
2. setTimeout
+ условный рекурсии
для двух нижних вариантов мы делаем свои собственные циклы, поэтому нам придется самим отслеживать индекс, инициализируя его на нуле и увеличивая на всем протяжении.
для этого, мы будем a) вызов setTimeout
который будет выполняться один раз, b) оцените массив в позиции индекса, c) проверьте, есть ли больше элементов в массиве, и если да, начните с (ля.)
function ArrayPlusDelay(array, delegate, delay) {
var i = 0
function loop() {
// each loop, call passed in function
delegate(array[i]);
// increment, and if we're still here, call again
if (i++ < array.length - 1)
setTimeout(loop, delay); //recursive
}
// seed first call
setTimeout(loop, delay);
}
// call like this
ArrayPlusDelay(['d','e','f'], function(obj) {console.log(obj)},1000)
3. setInterval
+ условный clearInterval
Примечание функция setInterval
будет работать вечно, когда-то называли. Это возвращаемое значение, когда изначально установлено, будет содержать ссылку на интервал, поэтому оно часто сочетается с функцией clearInterval
по желанию отключить его по дороге
function ArrayPlusDelay(array, delegate, delay) {
var i = 0
// seed first call and store interval (to clear later)
var interval = setInterval(function() {
// each loop, call passed in function
delegate(array[i]);
// increment, and if we're past array, clear interval
if (i++ >= array.length - 1)
clearInterval(interval);
}, delay)
}
ArrayPlusDelay(['x','y','z'], function(obj) {console.log(obj)},1000)
3* Секретный Четвертый Вариант (Лучший)
опции 1 и 2 рискованны, потому что, как только вы отправите этот поезд, нет возможности отменить его по дороге (сохранить закрытие браузера). Если у вас большой массив или большая нагрузка в вашем делегате, было бы неплохо предоставить некоторый ресурс, если вам это нужно. Сохранив ссылку из setInterval
, у нас будет постоянный доступ к итерационной функции. Нам просто нужно вернуть объект interval выше и сохранить его при вызове нашего массива plus delay функция.
function ArrayPlusDelay(array, delegate, delay) {
var i = 0
// seed first call and store interval (to clear later)
var interval = setInterval(function() {
// each loop, call passed in function
delegate(array[i]);
// increment, and if we're past array, clear interval
if (i++ >= array.length - 1)
clearInterval(interval);
}, delay)
return interval
}
var inter = ArrayPlusDelay(['x','y','z'], function(obj) {console.log(obj)},1000)
тогда, если мы когда-нибудь захотим очистить его позже, просто бросьте это в консоль:
clearInterval(inter);
все 3 демонстрации в jsFiddle
Подобные Вопросы Переполнения Стека:
each
обычно лучше для вещей, которые происходят немедленно.
вместо этого, если вы не против изменить массив, вы можете использовать его в качестве очереди:
var ary = ['kevin', 'mike', 'sally'];
setTimeout(function loop() {
console.log(ary.shift());
if (ary.length)
setTimeout(loop, 5000);
}, 5000);
он продолжает звонить loop
5 секунд в будущем, пока в очереди ничего не останется.
вы можете просто использовать setInterval () С простым счетчиком увеличения на один.
var ary = ['kevin', 'mike', 'sally'];
var i=0;
setInterval(function(){
console.log(ary[i]);
i++;
}, 5000);
но обратите внимание, что это начнет бросать ошибки после того, как i станет больше двух. У вас должна быть какая-то проверка и убедитесь, что вы очистили интервал.