J'aimerais ajouter un délai/sommeil dans une boucle while
:
J'ai essayé comme ça:
alert('hi');
for(var start = 1; start < 10; start++) {
setTimeout(function () {
alert('hello');
}, 3000);
}
Seul le premier scénario est vrai: après avoir affiché alert('hi')
, il attendra 3 secondes, puis alert('hello')
sera affiché, puis alert('hello')
sera à plusieurs reprises constamment.
Ce que j'aimerais, c'est qu'après que alert('hello')
soit affiché 3 secondes après alert('hi')
, il doit attendre 3 secondes pour la deuxième fois alert('hello')
et ainsi de suite.
La fonction setTimeout()
est non bloquante et reviendra immédiatement. Par conséquent, votre boucle itérera très rapidement et déclenchera rapidement des déclenchements de temporisation de 3 secondes les uns après les autres. C'est pourquoi vos premières alertes apparaissent au bout de 3 secondes et tout le reste s'enchaîne sans délai.
Vous voudrez peut-être utiliser quelque chose comme ceci à la place:
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
Vous pouvez également le nettoyer en utilisant une fonction d'invocation automatique, en passant le nombre d'itérations sous forme d'argument:
(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
Essayez quelque chose comme ça:
var i = 0, howManyTimes = 10;
function f() {
alert( "hi" );
i++;
if( i < howManyTimes ){
setTimeout( f, 3000 );
}
}
f();
Si vous utilisez ES6, vous pouvez utiliser let
pour y parvenir:
for (let i=1; i<10; i++) {
setTimeout( function timer(){
alert("hello world");
}, i*3000 );
}
Ce que let
fait est de déclarer i
pour chaque itération , pas la boucle. De cette façon, ce qui est passé à setTimeout
correspond exactement à ce que nous voulons.
Une autre méthode consiste à multiplier le délai d’expiration, mais notez que c’est pas comme dormir . Code après l'exécution de la boucle immédiatement, seule l'exécution de la fonction de rappel est différée.
for (var start = 1; start < 10; start++)
setTimeout(function () { alert('hello'); }, 3000 * start);
Le premier délai sera défini sur 3000 * 1
, le second sur 3000 * 2
et ainsi de suite.
Depuis ES7, il existe un meilleur moyen de wait une boucle:
function timer(ms) {
return new Promise(res => setTimeout(res, ms));
}
async function load () {
for (var i = 0; i < 3; i++) {
console.log(i);
await timer(3000);
}
}
load();
Notez qu'ES7 est rarement pris en charge aujourd'hui, vous devez donc utiliser Babel pour pouvoir l'utiliser partout.
Je pense que vous avez besoin de quelque chose comme ça:
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;
}
}
Code de test:
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();
Remarque: l'utilisation des alertes bloque l'exécution du code javascript jusqu'à la fermeture de l'alerte ... Il peut s'agir de plus de code que ce que vous avez demandé, mais il s'agit d'une solution réutilisable robuste.
J'utiliserais probablement setInteval
. Comme ça,
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);
Ça va marcher
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() { console.log(i); }, 100 * i);
})(i);
}
Essayez ce violon: https://jsfiddle.net/wgdx8zqq/
Dans ES6 (ECMAScript 2015), vous pouvez effectuer une itération avec délai avec generator et interval.
Les générateurs, une nouvelle fonctionnalité de ECMAScript 6, sont des fonctions qui peuvent être. suspendu et repris. L'appel de genFunc ne l'exécute pas. Au lieu de cela, il retourne un objet générateur qui nous permet de contrôler .f. de genFunc. exécution. genFunc () est initialement suspendu au début de son corps. La méthode genObj.next () continue l'exécution de genFunc, jusqu'au prochain rendement . (Exploring ES6)
Exemple de code:
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;
}
}
Donc, si vous utilisez ES6, c’est le moyen le plus élégant de réaliser une boucle avec délai (à mon avis).
Je le fais avec le Promise.delay
et la récursion de Bluebird.
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>
Je pensais juste poster mes deux cents ici aussi. Cette fonction exécute une boucle itérative avec un délai. Voir ce jsfiddle . La fonction est la suivante:
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)
}
}
Par exemple:
//This function prints the loop number every second
timeout([0, 5], 1, function(i){
console.log(i);
});
Serait équivalent à:
//This function prints the loop number instantly
for (var i = 0; i<5; i++){
console.log(i);
}
Vous pouvez utiliser l'opérateur RxJS intervalle . Intervalle émet un entier toutes les x secondes et prend le nombre de fois qu'il doit émettre des nombres
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>
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);
Une version modifiée de la réponse de Daniel Vassallo, avec des variables extraites dans des paramètres pour rendre la fonction plus réutilisable:
Commençons par définir quelques variables essentielles:
var startIndex = 0;
var data = [1, 2, 3];
var timeout = 3000;
Ensuite, vous devez définir la fonction que vous souhaitez exécuter. Cela passera i, l'index actuel de la boucle et la longueur de la boucle, au cas où vous en auriez besoin:
function functionToRun(i, length) {
alert(data[i]);
}
Version à exécution automatique
(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);
Version fonctionnelle
function forWithDelay(i, length, fn, delay) {
setTimeout(function () {
fn(i, length);
i++;
if (i < length) {
forWithDelay(i, length, fn, delay);
}
}, delay);
}
forWithDelay(startIndex, data.length, functionToRun, timeout); // Lets run it
Tu le fais:
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>
Mise en œuvre simple: affichage d'un morceau de texte toutes les deux secondes tant que la boucle est en cours d'exécution.
for (var i = 0; i < foo.length; i++) {
setInterval(function(){
console.log("I will appear every 2 seconds");
}, 2000);
break;
};
Voici comment j'ai créé une boucle infinie avec un délai qui se rompt à certaines conditions:
// Now continuously check the app status until it's 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));
}
}
La clé ici est de créer une nouvelle promesse résolue par délai d'attente et d'attendre qu'elle soit résolue.
De toute évidence, vous avez besoin d’un soutien asynchrone/wait pour cela. Fonctionne dans le nœud 8.
<!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>
pour une utilisation commune "oublier les boucles normales" et utiliser cette combinaison de "setInterval" inclut "setTimeOut": comme ceci (de mes tâches réelles).
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: Comprenez que le comportement réel de (setTimeOut): ils vont tous commencer dans le même temps "les trois bla bla bla commenceront à décompter au même moment" alors faites un temps différent pour organiser l'exécution.
PS 2: l'exemple pour la boucle de synchronisation, mais pour une boucle de réaction, vous pouvez utiliser des événements, promettez en attente asynchrone.
À ma connaissance, la fonction setTimeout
est appelée de manière asynchrone. Ce que vous pouvez faire est d’envelopper la boucle entière dans une fonction asynchrone et d’attendre une Promise
contenant le setTimeout comme indiqué:
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;
}
Et puis vous appelez le lancer comme ça:
looper().then(function(){
console.log("DONE!")
});
Veuillez prendre le temps de bien comprendre la programmation asynchrone.
/*
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
*/