Question

Je pensais que j'essayer d'être intelligent et crée une fonction d'attente de mon propre (je me rends compte qu'il ya d'autres façons de le faire). Donc, je l'ai écrit:

var interval_id;
var countdowntimer = 0;

function Wait(wait_interval) {
  countdowntimer = wait_interval;

  interval_id = setInterval(function() {
    --countdowntimer <=0 ? clearInterval(interval_id) : null;
  }, 1000);

  do {} while (countdowntimer >= 0);
}

// Wait a bit: 5 secs
Wait(5);

tous les travaux, à l'exception de la boucle infinie. Lors de l'inspection, si je prends la boucle While dehors, la fonction anonyme est entré 5 fois, comme prévu. Il apparaît donc clairement la variable globale countdowntimer est décrémenté.

Cependant, si je vérifie la valeur de countdowntimer , dans la boucle While, il ne se couche jamais. Ceci malgré le fait que la fonction anonyme est appelée alors que dans la boucle while!

Il est clair que, d'une certaine manière, il y a deux valeurs de countdowntimer flottant autour, mais pourquoi?

EDIT

Ok, donc je comprends (maintenant) que Javascript est seul thread. Et que - en quelque sorte - répond à ma question. Mais, à quel moment le traitement de ce fil unique, fait que l'on appelle appel asynchrone en utilisant setInterval en fait se produire? Est-il juste entre les appels de fonction? Sûrement pas, qu'en est-fonctions qui prennent beaucoup de temps pour exécuter?

Était-ce utile?

La solution

Il n'y a pas deux copies de la variable se trouvant autour. Javascript dans les navigateurs web est un seul thread (sauf si vous utilisez le nouveaux travailleurs web trucs ). Ainsi, la fonction anonyme n'a jamais la chance de courir, parce que Wait est liais l'interprète.

Vous ne pouvez pas utiliser les fonctions-attente occupés en Javascript basé sur un navigateur; rien d'autre ne se fera jamais (et ils sont une mauvaise idée dans la plupart des environnements, même là où ils sont possibles). Vous devez utiliser callbacks à la place. Voici un remaniement minimaliste que:

var interval_id;
var countdowntimer = 0;

function Wait(wait_interval, callback) {
    countdowntimer = wait_interval;

    interval_id = setInterval(function() {
        if (--countdowntimer <=0) {
            clearInterval(interval_id);
            interval_id = 0;
            callback();
        }
    }, 1000);
}

// Wait a bit: 5 secs
Wait(5, function() {
    alert("Done waiting");
});

// Any code here happens immediately, it doesn't wait for the callback

Modifier Répondre à votre suivi:

  

Mais, à quel moment le traitement de ce seul fil, ne le soi-disant appel asynchrone en utilisant setInterval réellement se produire? Est-il juste entre les appels de fonction? Sûrement pas, qu'en est-fonctions qui prennent beaucoup de temps pour exécuter?

Quasiment, oui - et il est donc important que les fonctions ne soient pas de longue durée. (Techniquement, il est même pas entre les appels de fonction, en ce que si vous avez une fonction qui appelle trois autres fonctions, l'interprète ne peut rien faire d'autre pendant cette fonction (externe) est en cours d'exécution.) L'interprète maintient essentiellement une file d'attente des fonctions dont il a besoin éxécuter. Il commence commence en exécutant un code global (plutôt comme un grand appel de fonction). Puis, quand les choses se passent (événements d'entrée d'utilisateur, le temps d'appeler un rappel programmé via setTimeout est atteinte, etc.), l'interprète repousse les appels dont il a besoin de faire sur la file d'attente. Il traite toujours l'appel à l'avant de la file d'attente, et donc les choses peuvent empiler (comme vos appels setInterval, bien que setInterval est bits spécial - il ne sera pas la file d'attente d'un rappel ultérieur si un précédent est encore assis dans la file d'attente en attente à traiter). Alors, pensez en termes de quand votre code prend le contrôle et quand il libère le contrôle (par exemple, en retournant). L'interprète peut que faire d'autres choses après avoir relâché le contrôle et avant qu'il ne lui donne de nouveau à vous. Et encore, sur certains navigateurs (IE, par exemple), ce même fil est également utilisé pour la peinture de l'interface utilisateur et par exemple, si des insertions DOM (par exemple) ne sera pas affiché jusqu'à ce que vous relâchiez de retour de commande au navigateur afin qu'il puisse obtenir avec faire sa peinture.

Javascript dans les navigateurs Web, vous avez vraiment besoin d'adopter une approche événementielle à la conception et le codage de vos solutions. L'exemple classique est invite l'utilisateur à l'information. Dans un monde non-événement axé, vous pouvez faire ceci:

// Non-functional non-event-driven pseudo-example
askTheQuestion();
answer = readTheAnswer();      // Script pauses here
doSomethingWithAnswer(answer); // This doesn't happen until we have an answer
doSomethingElse();

Cela ne fonctionne pas dans un monde événementiel. , Vous faites place à ceci:

askTheQuestion();
setCallbackForQuestionAnsweredEvent(doSomethingWithAnswer);
// If we had code here, it would happen *immediately*,
// it wouldn't wait for the answer

Ainsi, par exemple, askTheQuestion peut superposer une div sur la page avec les champs demander à l'utilisateur diverses informations avec un bouton « OK » pour eux de cliquer quand ils sont fait. setCallbackForQuestionAnswered serait vraiment accrochait l'événement click sur le bouton « OK ». doSomethingWithAnswer recueillerait les informations des champs, supprimer ou cacher la div, et faire quelque chose avec l'info.

Autres conseils

La plupart application Javascript sont un seul thread , donc quand il exécute la boucle de while, il ne laisse rien d'autre exécuter, de sorte que le interval ne fonctionne jamais alors que le while est en cours d'exécution, rendant ainsi un infini boucle.

Il y a de nombreuses tentatives similaires pour créer un sommeil / attente / pause fonction en javascript, mais puisque la plupart des implémentations sont un seul thread, il suffit de ne vous laissez pas faire autre chose pendant le sommeil (!) .

La voie alternative de faire un retard est d'écrire les délais d'attente . Ils peuvent reporter l'exécution d'un morceau de code, mais vous devez le casser dans de nombreuses fonctions. Vous pouvez toujours les fonctions inline il est donc plus facile de suivre (et aux variables d'actions dans le même contexte d'exécution).

Il y a aussi quelques bibliothèques qui ajoute quelques syntactique suggar à javascript rendant ce plus facile à lire.

EDIT: Il y a un billet de blog par excelent John Resig Comment javascript minuteries travail . Il explique à peu près dans les détails. Espérons que cela aide.

En fait, à peu près la garantie que la fonction d'intervalle ne sera jamais exécuté alors que la boucle fait comme javascript est mono-thread.

Il y a une raison pour laquelle personne ne l'a fait Wait avant (et donc beaucoup ont essayé); il ne peut simplement pas être fait.

Vous devrez recourir à freiner votre fonction en bits et planifier ces utilisant setTimeout ou setInterval.

//first part
...
setTimeout(function(){
    //next part
}, 5000/*ms*/);

En fonction de vos besoins cela pourrait (devrait) être mis en œuvre en tant que machine d'état.

Au lieu d'utiliser une variable globale countdowntimer, pourquoi ne pas simplement changer l'attribut milliseconde sur la place setInterval? Quelque chose comme:

var waitId;

function Wait(waitSeconds)
{
    waitId= setInterval(function(){clearInterval(waitId);}, waitSeconds * 1000);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top