Я хотел бы добавить задержку/сон внутри в while
цикла:
Я попробовал это так:
alert('hi');
for(var start = 1; start < 10; start++) {
setTimeout(function () {
alert('hello');
}, 3000);
}
Только первый сценарий верно: после того, как показывает alert('hi')
, он будет ждать в течение 3 секунд, а затем alert('hello')
будет отображаться, но затем alert('hello')
будет повторно постоянно.
Мне хотелось бы, чтобы после alert('hello')
показано через 3 секунды после alert('hi')
тогда ему нужно ждать 3 секунды для второго alert('hello')
и так далее.
Ответ 1
Функция setTimeout()
не блокирует и немедленно вернется. Поэтому ваш цикл будет очень быстро итеративно, и он будет запускать три-трижды триггеры таймаута один за другим в быстрой последовательности. Вот почему ваши первые предупреждения появляются через 3 секунды, а все остальные следуют последовательно без каких-либо задержек.
Вместо этого вы можете использовать что-то вроде этого:
var i = 1; // set your counter to 1
function myLoop () { // create a loop function
setTimeout(function () { // call a 3s setTimeout when the loop is called
alert('hello'); // your code here
i++; // increment the counter
if (i < 10) { // if the counter < 10, call the loop function
myLoop(); // .. again which will trigger another
} // .. setTimeout()
}, 3000)
}
myLoop(); // start the loop
Вы могли бы также аккуратно его использовать, используя функцию self invoking, передавая количество итераций в качестве аргумента:
(function myLoop (i) {
setTimeout(function () {
alert('hello'); // your code here
if (--i) myLoop(i); // decrement i and call myLoop again if i > 0
}, 3000)
})(10); // pass the number of iterations as an argument
Ответ 2
Попробуйте что-то вроде этого:
var i = 0, howManyTimes = 10;
function f() {
alert( "hi" );
i++;
if( i < howManyTimes ){
setTimeout( f, 3000 );
}
}
f();
Ответ 3
Если вы используете ES6, вы можете использовать let
для этого:
for (let i=1; i<10; i++) {
setTimeout( function timer(){
alert("hello world");
}, i*3000 );
}
То, что let
делает, объявляет i
для каждой итерации, а не цикла. Таким образом, то, что передается setTimeout
, именно то, что мы хотим.
Ответ 4
Начиная с ES7, есть лучший способ ожидания цикла:
// Returns a Promise that resolves after "ms" Milliseconds
function timer(ms) {
return new Promise(res => setTimeout(res, ms));
}
async function load () { // We need to wrap the loop into an async function for this to work
for (var i = 0; i < 3; i++) {
console.log(i);
await timer(3000); // then the created Promise can be awaited
}
}
load();
Когда двигатель достигает части await
, он устанавливает тайм-аут и останавливает выполнение async function
. Затем по истечении времени ожидания выполнение продолжается в этой точке. Это очень полезно, поскольку вы можете задерживать (1) вложенные циклы, (2) условно, (3) вложенные функции:
async function task(i) { // 3
await timer(1000);
console.log('Task ${i} done!');
}
async function main() {
for(let i = 0; i < 100; i+= 10) {
for(let j = 0; j < 10; j++) { // 1
if(j % 2) { // 2
await task(i + j);
}
}
}
}
main();
function timer(ms) { return new Promise(res => setTimeout(res, ms)); }
Ответ 5
Другой способ - умножить время на таймаут, но обратите внимание, что это не похоже на sleep. Код после того, как цикл будет выполнен немедленно, выполняется только выполнение функции обратного вызова.
for (var start = 1; start < 10; start++)
setTimeout(function () { alert('hello'); }, 3000 * start);
Первый тайм-аут будет установлен на 3000 * 1
, второй - на 3000 * 2
и т.д.
Ответ 6
Я думаю, вам нужно что-то вроде этого:
var TimedQueue = function(defaultDelay){
this.queue = [];
this.index = 0;
this.defaultDelay = defaultDelay || 3000;
};
TimedQueue.prototype = {
add: function(fn, delay){
this.queue.push({
fn: fn,
delay: delay
});
},
run: function(index){
(index || index === 0) && (this.index = index);
this.next();
},
next: function(){
var self = this
, i = this.index++
, at = this.queue[i]
, next = this.queue[this.index]
if(!at) return;
at.fn();
next && setTimeout(function(){
self.next();
}, next.delay||this.defaultDelay);
},
reset: function(){
this.index = 0;
}
}
Тестовый код:
var now = +new Date();
var x = new TimedQueue(2000);
x.add(function(){
console.log('hey');
console.log(+new Date() - now);
});
x.add(function(){
console.log('ho');
console.log(+new Date() - now);
}, 3000);
x.add(function(){
console.log('bye');
console.log(+new Date() - now);
});
x.run();
Примечание: использование предупреждений закрывает выполнение javascript до закрытия предупреждения.
Это может быть больше кода, чем вы просили, но это надежное многоразовое решение.
Ответ 7
Я бы использовал setInteval
. Как это,
var period = 1000; // ms
var endTime = 10000; // ms
var counter = 0;
var sleepyAlert = setInterval(function(){
alert('Hello');
if(counter === endTime){
clearInterval(sleepyAlert);
}
counter += period;
}, period);
Ответ 8
Это будет работать
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() { console.log(i); }, 100 * i);
})(i);
}
Попробуйте эту скрипту: https://jsfiddle.net/wgdx8zqq/
Ответ 9
В ES6 (ECMAScript 2015) вы можете выполнять итерацию с задержкой generator и интервал.
Генераторы, новая функция ECMAScript 6, являются функциями, которые могут быть приостановлен и возобновлен. Вызов genFunc не выполняет его. Вместо этого возвращает так называемый объект-генератор, который позволяет нам управлять genFuncs выполнение. genFunc() первоначально приостанавливается в начале его тело. Метод genObj.next() продолжает выполнение genFunc, до следующего урожая. (Изучение ES6)
Пример кода:
let arr = [1, 2, 3, 'b'];
let genObj = genFunc();
let val = genObj.next();
console.log(val.value);
let interval = setInterval(() => {
val = genObj.next();
if (val.done) {
clearInterval(interval);
} else {
console.log(val.value);
}
}, 1000);
function* genFunc() {
for(let item of arr) {
yield item;
}
}
Ответ 10
Я делаю это с Bluebirds Promise.delay
и рекурсией.
function myLoop(i) {
return Promise.delay(1000)
.then(function() {
if (i > 0) {
alert('hello');
return myLoop(i -= 1);
}
});
}
myLoop(3);
<script src="//cdnjs.cloudflare.com/ajax/libs/bluebird/2.9.4/bluebird.min.js"></script>
Ответ 11
Просто подумал, что я разместил здесь свои два цента. Эта функция выполняет итеративный цикл с задержкой. См. этот jsfiddle. Функция следующая:
function timeout(range, time, callback){
var i = range[0];
callback(i);
Loop();
function Loop(){
setTimeout(function(){
i++;
if (i<range[1]){
callback(i);
Loop();
}
}, time*1000)
}
}
Например:
//This function prints the loop number every second
timeout([0, 5], 1, function(i){
console.log(i);
});
Будет эквивалентен:
//This function prints the loop number instantly
for (var i = 0; i<5; i++){
console.log(i);
}
Ответ 12
Вы можете использовать RxJS оператор интервала. Интервал испускает целое число каждые x секунд, а take указывает количество раз, когда он должен испускать числа
Rx.Observable
.interval(1000)
.take(10)
.subscribe((x) => console.log(x))
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.lite.min.js"></script>
Ответ 13
var startIndex = 0;
var data = [1, 2, 3];
var timeout = 1000;
function functionToRun(i, length) {
alert(data[i]);
}
(function forWithDelay(i, length, fn, delay) {
setTimeout(function() {
fn(i, length);
i++;
if (i < length) {
forWithDelay(i, length, fn, delay);
}
}, delay);
})(startIndex, data.length, functionToRun, timeout);
Ответ 14
/*
Use Recursive and setTimeout
call below function will run loop loopFunctionNeedCheck until
conditionCheckAfterRunFn = true, if conditionCheckAfterRunFn == false : delay
reRunAfterMs miliseconds and continue loop
tested code, thanks
*/
function functionRepeatUntilConditionTrue(reRunAfterMs, conditionCheckAfterRunFn,
loopFunctionNeedCheck) {
loopFunctionNeedCheck();
var result = conditionCheckAfterRunFn();
//check after run
if (!result) {
setTimeout(function () {
functionRepeatUntilConditionTrue(reRunAfterMs, conditionCheckAfterRunFn, loopFunctionNeedCheck)
}, reRunAfterMs);
}
else console.log("completed, thanks");
//if you need call a function after completed add code call callback in here
}
//passing-parameters-to-a-callback-function
// From Prototype.js
if (!Function.prototype.bind) { // check if native implementation available
Function.prototype.bind = function () {
var fn = this, args = Array.prototype.slice.call(arguments),
object = args.shift();
return function () {
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
};
};
}
//test code:
var result = 0;
console.log("---> init result is " + result);
var functionNeedRun = function (step) {
result+=step;
console.log("current result is " + result);
}
var checkResultFunction = function () {
return result==100;
}
//call this function will run loop functionNeedRun and delay 500 miliseconds until result=100
functionRepeatUntilConditionTrue(500, checkResultFunction , functionNeedRun.bind(null, 5));
//result log from console:
/*
---> init result is 0
current result is 5
undefined
current result is 10
current result is 15
current result is 20
current result is 25
current result is 30
current result is 35
current result is 40
current result is 45
current result is 50
current result is 55
current result is 60
current result is 65
current result is 70
current result is 75
current result is 80
current result is 85
current result is 90
current result is 95
current result is 100
completed, thanks
*/
Ответ 15
Вот как я создал бесконечный цикл с задержкой, которая ломается при определенном условии:
// Now continuously check the app status until it completed,
// failed or times out. The isFinished() will throw exception if
// there is a failure.
while (true) {
let status = await this.api.getStatus(appId);
if (isFinished(status)) {
break;
} else {
// Delay before running the next loop iteration:
await new Promise(resolve => setTimeout(resolve, 3000));
}
}
Ключевым моментом здесь является создание нового обещания, которое разрешается с помощью тайм-аута и ждать его разрешения.
Очевидно, вам нужна поддержка async/await. Работает в Node 8.
Ответ 16
для общего использования "забудьте обычные циклы", и эта комбинация "setInterval" включает в себя "setTimeOut": как это (из моих реальных задач).
function iAsk(lvl){
var i=0;
var intr =setInterval(function(){ // start the loop
i++; // increment it
if(i>lvl){ // check if the end round reached.
clearInterval(intr);
return;
}
setTimeout(function(){
$(".imag").prop("src",pPng); // do first bla bla bla after 50 millisecond
},50);
setTimeout(function(){
// do another bla bla bla after 100 millisecond.
seq[i-1]=(Math.ceil(Math.random()*4)).toString();
$("#hh").after('<br>'+i + ' : rand= '+(Math.ceil(Math.random()*4)).toString()+' > '+seq[i-1]);
$("#d"+seq[i-1]).prop("src",pGif);
var d =document.getElementById('aud');
d.play();
},100);
setTimeout(function(){
// keep adding bla bla bla till you done :)
$("#d"+seq[i-1]).prop("src",pPng);
},900);
},1000); // loop waiting time must be >= 900 (biggest timeOut for inside actions)
}
PS: Поймите, что реальное поведение (setTimeOut): все они начнутся в одно и то же время "три bla bla bla начнут отсчитывать в тот же момент", поэтому сделайте другой тайм-аут, чтобы организовать выполнение.
PS 2: пример цикла синхронизации, но для циклов реакции вы можете использовать события, обещая асинхронное ожидание.
Ответ 17
<!DOCTYPE html>
<html>
<body>
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
<script>
function myFunction() {
for(var i=0; i<5; i++) {
var sno = i+1;
(function myLoop (i) {
setTimeout(function () {
alert(i); // Do your function here
}, 1000*i);
})(sno);
}
}
</script>
</body>
</html>
Ответ 18
Насколько мне известно, функция setTimeout
вызывается асинхронно. Что вы можете сделать, это обернуть весь цикл в асинхронную функцию и ждать Promise
, который содержит setTimeout, как показано ниже:
var looper = async function () {
for (var start = 1; start < 10; start++) {
await new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("iteration: " + start.toString());
resolve(true);
}, 1000);
});
}
return true;
}
А потом вы вызываете запустить его так:
looper().then(function(){
console.log("DONE!")
});
Пожалуйста, уделите некоторое время, чтобы получить хорошее представление об асинхронном программировании.
Ответ 19
Вы делаете это:
alert('hi')
let start = 1
setTimeout(function(){
let interval = setInterval(function(){
if(start == 10) clearInterval(interval)
start++
alert('hello')
}, 3000)
}, 3000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Ответ 20
let counter =1;
for(let item in items) {
counter++;
setTimeout(()=>{
//your code
},counter*5000); //5Sec delay between each iteration
}
Ответ 21
Вот функция, которую я использую для циклического перемещения по массиву:
function loopOnArrayWithDelay(theArray, delayAmount, i, theFunction, onComplete){
if (i < theArray.length && typeof delayAmount == 'number'){
console.log("i "+i);
theFunction(theArray[i], i);
setTimeout(function(){
loopOnArrayWithDelay(theArray, delayAmount, (i+1), theFunction, onComplete)}, delayAmount);
}else{
onComplete(i);
}
}
Вы используете его следующим образом:
loopOnArrayWithDelay(YourArray, 1000, 0, function(e, i){
//Do something with item
}, function(i){
//Do something once loop has completed
}
Ответ 22
Этот script работает для большинства вещей
function timer(start) {
setTimeout(function () { //The timer
alert('hello');
}, start*3000); //needs the "start*" or else all the timers will run at 3000ms
}
for(var start = 1; start < 10; start++) {
timer(start);
}
Ответ 23
var timer, i = 10;
function myLoop () { // create a loop function
timer = setTimeout(function () {
document.getElementById("demo").innerHTML = i;
i--;
if (i >= 0) {
myLoop();
} else {
clearTimeout(timer); // clear timeout
document.getElementById("demo").innerHTML = "DOARRRR ..";
}
}, 1000);
}
myLoop();
<p id="demo">count</p>
Ответ 24
Попробуй это...
var icount=0;
for (let i in items) {
icount=icount+1000;
new beginCount(items[i],icount);
}
function beginCount(item,icount){
setTimeout(function () {
new actualFunction(item,icount);
}, icount);
}
function actualFunction(item,icount){
//...runs ever 1 second
console.log(icount);
}
Ответ 25
Простая реализация показа фрагмента текста каждые две секунды, пока работает цикл.
for (var i = 0; i < foo.length; i++) {
setInterval(function(){
console.log("I will appear every 2 seconds");
}, 2000);
break;
};
Ответ 26
Попробуйте это
//the code will execute in 1 3 5 7 9 seconds later
function exec(){
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(new Date()); //It you code
},(i+i+1)*1000);
}
}