Attendez 5 secondes avant d'exécuter la ligne suivante

313

Cette fonction ci-dessous ne fonctionne pas comme je le souhaite; étant un novice JS, je ne peux pas comprendre pourquoi.

J'en ai besoin pour attendre 5 secondes avant de vérifier si newStatec'est le cas -1.

Actuellement, il n'attend pas, il vérifie tout de suite.

function stateChange(newState) {
  setTimeout('', 5000);

  if(newState == -1) {
    alert('VIDEO HAS STOPPED');
  }
}
flocon
la source

Réponses:

323

Vous devez mettre votre code dans la fonction de rappel que vous fournissez à setTimeout:

function stateChange(newState) {
    setTimeout(function () {
        if (newState == -1) {
            alert('VIDEO HAS STOPPED');
        }
    }, 5000);
}

Tout autre code s'exécutera immédiatement.

Joseph Silber
la source
4
Le principal problème est que dans certains cas (en particulier les tests), cela est terriblement inadéquat. Que se passe-t-il si vous devez dormir pendant 500 ms avant de revenir de la fonction, par exemple pour simuler une requête http asynchrone lente ?
A.Grandt
14
Si par «test» vous entendez des tests unitaires: votre framework de test devrait avoir un moyen d'exécuter des tests asynchrones. Si vous parlez de tests manuels: l'onglet Réseau de Chrome a une liste déroulante de limitation pour simuler les demandes lentes.
Joseph Silber
1
que faire si je développe une extension chrome et que la dernière valeur évaluée dans le script injecté devrait me donner le résultat; et j'ai besoin de quelques retards?
mirek
184

Vous ne devriez vraiment pas faire cela , l'utilisation correcte du délai d'attente est le bon outil pour le problème de l'OP et toute autre occasion où vous voulez simplement exécuter quelque chose après un certain temps. Joseph Silber l'a bien démontré dans sa réponse. Cependant, si dans certains cas non liés à la production, vous voulez vraiment suspendre le thread principal pendant un certain temps, cela le fera.

function wait(ms){
   var start = new Date().getTime();
   var end = start;
   while(end < start + ms) {
     end = new Date().getTime();
  }
}

Avec exécution sous la forme:

console.log('before');
wait(7000);  //7 seconds in milliseconds
console.log('after');

Je suis arrivé ici parce que je construisais un cas de test simple pour séquencer un mélange d'opérations asynchrones autour d'opérations de blocage de longue durée (c'est-à-dire une manipulation DOM coûteuse) et c'est mon opération de blocage simulée. Cela convient parfaitement à ce travail, j'ai donc pensé le publier pour toute autre personne qui arrive ici avec un cas d'utilisation similaire. Même ainsi, cela crée un objet Date () dans une boucle while, ce qui pourrait submerger le GC s'il fonctionne suffisamment longtemps. Mais je ne saurais trop insister, cela ne convient que pour les tests, pour construire une fonctionnalité réelle, vous devriez vous référer à la réponse de Joseph Silber.

Micro
la source
7
Cela n'arrêtera pas l'exécution de javascript.
Terry Lin
23
@TerryLin Essayez de l'exécuter.
Mic
6
Donc, fondamentalement, vous perdez du temps CPU. Ce n'est pas une attente car vous ne mettez pas le thread en mode veille pour permettre au processeur principal de se concentrer sur d'autres tâches.
Kyordhel
6
@Gzork Thread sleep n'est qu'une façon d'implémenter une fonction d'attente, et elle n'est malheureusement pas disponible dans le contexte du javascript côté client. Cependant, si vous pensez que d'autres tâches asynchrones dans le client seront terminées pendant son exécution, vous ne l'avez évidemment pas testé. Bien que je l'utilise dans le fil principal, je mets en place un violon illustrant comment même si cela est appelé via un setTimeout en premier lieu, il interrompt toujours d'autres événements asynchrones jsfiddle.net/souv51v3/1 - vous trouverez même le La fenêtre JSFiddle elle-même ne répond plus lorsqu'elle se termine.
Mic
1
Horrible solution à mon humble avis - porcs CPU pendant qu'il "dort". La bonne façon de dormir est via async / attendez ala cette réponse stackoverflow.com/questions/951021/… ou Etienne.
David Simic
164

Voici une solution utilisant la nouvelle syntaxe async / wait .

Assurez-vous de vérifier la prise en charge du navigateur car il s'agit d'une nouvelle fonctionnalité introduite avec ECMAScript 6.

Fonction d'utilité:

const delay = ms => new Promise(res => setTimeout(res, ms));

Usage:

const yourFunction = async () => {
  await delay(5000);
  console.log("Waited 5s");

  await delay(5000);
  console.log("Waited an additional 5s");
};

L'avantage de cette approche est qu'elle donne à votre code l'apparence et le comportement d'un code synchrone.

Etienne Martin
la source
Vous n'avez pas besoin d'ECMAScript 6: Si vous utilisez déjà des promesses pour effectuer le chargement asynchrone et que vous souhaitez simplement imiter une partie de la chaîne en prenant du temps, vous pouvez ajouter cette fonction wait () à la chaîne.
Dovev Hefetz
2
C'est vraiment la meilleure réponse avec la nouvelle syntaxe. J'ai eu des problèmes avec l'utilisation de la solution wait () ci-dessus.
pianoman102
36

Vous ne devriez pas simplement essayer de faire une pause de 5 secondes en javascript. Cela ne fonctionne pas de cette façon. Vous pouvez planifier une fonction de code pour qu'elle s'exécute dans 5 secondes à partir de maintenant, mais vous devez mettre le code que vous souhaitez exécuter ultérieurement dans une fonction et le reste de votre code après cette fonction continuera à s'exécuter immédiatement.

Par exemple:

function stateChange(newState) {
    setTimeout(function(){
        if(newState == -1){alert('VIDEO HAS STOPPED');}
    }, 5000);
}

Mais, si vous avez un code comme celui-ci:

stateChange(-1);
console.log("Hello");

L' console.log()instruction s'exécutera immédiatement. Il n'attendra pas jusqu'à ce que la temporisation se déclenche dans la stateChange()fonction. Vous ne pouvez pas simplement suspendre l'exécution de javascript pendant une durée prédéterminée.

Au lieu de cela, tout code que vous voulez exécuter des retards doit être à l' intérieur de la setTimeout()fonction de rappel (ou appelé de cette fonction).

Si vous avez essayé de "mettre en pause" en boucle, alors vous "suspendriez" essentiellement l'interpréteur Javascript pendant un certain temps. Parce que Javascript exécute votre code dans un seul thread, lorsque vous bouclez, rien d'autre ne peut s'exécuter (aucun autre gestionnaire d'événements ne peut être appelé). Ainsi, le bouclage en attente de modification d'une variable ne fonctionnera jamais car aucun autre code ne peut s'exécuter pour modifier cette variable.

jfriend00
la source
31
Vous ne pouvez pas simplement suspendre l'exécution de javascript pendant une durée prédéterminée . Je pense que vous voulez dire que vous ne devriez pas, car vous pouvez (si vous voulez vous pendre):var t = new Date().getTime(); while (new Date().getTime() < t + millisecondsToLockupBrowser);
Joseph Silber
9
@JosephSilber - D'accord, vous pourriez le faire, mais en pratique cela ne fonctionne pas car de nombreux navigateurs afficheront une boîte de dialogue disant qu'un script ne répond plus ET que c'est une expérience utilisateur horrible et que c'est mauvais pour la durée de vie de la batterie et la page est pendu en faisant cela et ... Ce serait mauvais.
jfriend00
12
Bien sûr, ce serait horrible, et personne ne devrait jamais jamais jamais faire ça. Je ne pouvais tout simplement pas résister à mon "bien-être" intérieur . Désolé.
Joseph Silber
31

Si vous êtes dans une fonction asynchrone, vous pouvez simplement le faire en une seule ligne:

console.log(1);
await new Promise(resolve => setTimeout(resolve, 3000)); // 3 sec
console.log(2);

Remarquez , si la cible est NodeJS, il sera plus efficace de l'utiliser (c'est une fonction setTimeout prédéfinie promise):

await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000) // 3 sec
Shl
la source
Quelle est la différence entre les deux implémentations?
EAzevedo
1
Actuellement, il n'y a aucune différence. Mais si à un moment donné, le nœud décide de le rendre plus rapide / plus sûr / plus efficace, vous utiliserez la version du nœud js dès le départ. Bien que la lisibilité soit plus susceptible d'être le facteur clé pour la plupart des gens, dans ce cas, il vaut mieux utiliser la première façon.
Shl
Je vous remercie. Votre réponse a résolu un problème auquel je fais face depuis trois jours déjà. Merci.
EAzevedo
8

Essaye ça:

//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's you code
        },(i+i+1)*1000);
    }
}
Steve Jiang
la source
7

Meilleur moyen de créer une fonction comme celle-ci pour attendre en milli secondes, cette fonction attendra les millisecondes fournies dans l'argument:

function waitSeconds(iMilliSeconds) {
    var counter= 0
        , start = new Date().getTime()
        , end = 0;
    while (counter < iMilliSeconds) {
        end = new Date().getTime();
        counter = end - start;
    }
}

Jitendra Pal - JP
la source
3

Sur la base de la réponse de Joseph Silber , je le ferais comme ça, un peu plus générique.

Vous auriez votre fonction (créons-en une en fonction de la question):

function videoStopped(newState){
   if (newState == -1) {
       alert('VIDEO HAS STOPPED');
   }
}

Et vous pourriez avoir une fonction d'attente:

function wait(milliseconds, foo, arg){
    setTimeout(function () {
        foo(arg); // will be executed after the specified time
    }, milliseconds);
}

À la fin, vous auriez:

wait(5000, videoStopped, newState);

C'est une solution, je préfère ne pas utiliser d'arguments dans la fonction d'attente (pour n'en avoir qu'au foo();lieu de foo(arg);) mais c'est pour l'exemple.

Sylhare
la source
3

Cette solution provient de la documentation de React Native pour un contrôle de rafraîchissement :

function wait(timeout) {
    return new Promise(resolve => {
        setTimeout(resolve, timeout);
    });
}

Pour appliquer cela à la question du PO, vous pouvez utiliser cette fonction en coordination avec await:

await wait(5000);
if (newState == -1) {
    alert('Done');
}
bearacuda13
la source
1

Vous pouvez ajouter du retard en apportant de petites modifications à votre fonction (asynchronisation et attente).

const add5SecondsDelay = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('5 seconds');
    }, 50000);
  });
}

async function asyncFunctionCall() {

  console.log("stpe-1"); 
  const result = await add5SecondsDelay ();
  console.log("step-2 after 5 seconds delay"); 

}

asyncFunctionCall();
p.durga shankar
la source
-2

en utilisant angularjs:

$timeout(function(){
if(yourvariable===-1){
doSomeThingAfter5Seconds();
}
},5000)
Dr. Abbos
la source
-2

Créer une nouvelle fonction Js

function sleep(delay) {
        var start = new Date().getTime();
        while (new Date().getTime() < start + delay);
      }

Appelez la fonction lorsque vous souhaitez retarder l'exécution. Utilisez des millisecondes dans int pour la valeur de retard.

####Some code
 sleep(1000);
####Next line
Madushanka Sampath
la source
3
Cela consommera trop de ressources.
awavi
-2

Je l'ai utilisé pour exécuter des jeux PC depuis Edge ou IE. Et il ferme automatiquement IE Edge après 7 secondes.

Firefox et Google Chrome ne peuvent pas être utilisés pour démarrer des jeux de cette façon.

<html<body>
<a href="E:\game\game.exe" name="game" onmouseout="waitclose(7000);"> game
<img src="game.jpg" width="100%" height="97%" ></a>
<script>
function waitclose(ms){
 var start = new Date().getTime();var end=start;
 while(end < start + ms) {end = new Date().getTime();}
window.open('', '_self', ''); window.close();
}
</script>
</body></html>
user4565320
la source