web-dev-qa-db-fra.com

Comment implémenter un verrou en JavaScript

Comment un élément équivalent à lock en C # peut-il être implémenté en JavaScript?

Donc, pour expliquer ce que je pense, voici un cas d'utilisation simple: 

L'utilisateur clique sur le bouton B. B déclenche un événement onclick. Si B est dans event-state, l'événement attend que B soit dans ready-state avant de se propager. Si B est dans ready-state, B est verrouillé et défini sur event-state, l'événement se propage. Lorsque la propagation de l'événement est terminée, B est défini sur ready-state.

Je pouvais voir comment quelque chose de proche pourrait être fait, simplement en ajoutant et en supprimant la classe ready-state du bouton. Cependant, le problème est qu'un utilisateur peut cliquer sur un bouton deux fois de suite plus rapidement que la variable ne peut être définie. Cette tentative de verrouillage échouera dans certaines circonstances.

Est-ce que quelqu'un sait comment implémenter un verrou qui n'échouera pas en JavaScript?

63
smartcaveman

Le verrouillage est une idée discutable dans JS qui est conçue pour être sans thread et ne nécessitant pas de protection de concurrence. Vous souhaitez combiner des appels en exécution différée. Le modèle que je suis pour cela est l'utilisation de rappels. Quelque chose comme ça:

var functionLock = false;
var functionCallbacks = [];
var lockingFunction = function (callback) {
    if (functionLock) {
        functionCallbacks.Push(callback);
    } else {
        $.longRunning(function(response) {
             while(functionCallbacks.length){
                 var thisCallback = functionCallbacks.pop();
                 thisCallback(response);
             }
        });
    }
}

Vous pouvez également implémenter cela à l'aide d'écouteurs d'événement DOM ou d'une solution pubsub.

77
JoshRivers

JavaScript est, avec quelques exceptions _ (XMLHttpRequestonreadystatechange gestionnaires dans certaines versions de Firefox) concurrentes de boucles d’événements } _. Vous n'avez donc pas à vous soucier de verrouiller dans ce cas.

JavaScript a un modèle de concurrence basé sur une "boucle d'événement". Ce modèle est très différent de celui utilisé dans d'autres langages tels que C ou Java.

...

Un environnement d'exécution JavaScript contient une file d'attente de messages, qui est une liste des messages à traiter. A chaque message est associée une fonction. Lorsque la pile est vide, un message est retiré de la file d'attente et traité. Le traitement consiste à appeler la fonction associée (et à créer ainsi un cadre de pile initial). Le traitement du message se termine lorsque la pile redevient vide.

...

Chaque message est traité complètement avant tout autre message. Ceci offre certaines propriétés de Nice lors du raisonnement sur votre programme, notamment le fait que chaque fois qu'une fonction est exécutée, elle ne peut pas être anticipée et sera exécutée entièrement avant tout autre code (et peut modifier les données manipulées par la fonction). Ceci diffère de C, par exemple, où si une fonction est exécutée dans un thread, elle peut être arrêtée à tout moment pour exécuter un autre code dans un autre thread.

L'inconvénient de ce modèle est que si un message prend trop de temps, l'application Web ne peut pas traiter les interactions utilisateur telles que cliquer ou faire défiler. Le navigateur atténue cela avec la boîte de dialogue "l'exécution d'un script est trop longue". Une bonne pratique à suivre est de raccourcir le traitement des messages et, si possible, de réduire un message en plusieurs.

Pour plus de liens sur la simultanéité de boucle d'événement, voir E

26
Mike Samuel

Les serrures sont un concept requis dans un système multithread. Même avec les threads de travail, les messages sont envoyés par valeur entre les travailleurs, ce qui rend le verrouillage inutile.

Je suppose que vous devez simplement définir un sémaphore (système de signalisation) entre vos boutons.

6
James Westgate

J'ai eu du succès mutex-promise .

Je suis d’accord avec d’autres réponses pour dire que vous n’aurez peut-être pas besoin d’être bloqué dans votre cas. Mais ce n'est pas vrai qu'on n'a jamais besoin de verrouiller en Javascript. Vous avez besoin d'exclusivité mutuelle pour accéder à des ressources externes qui ne gèrent pas la simultanéité.

5
Tim Scott

Pourquoi ne désactivez-vous pas le bouton et ne l'activez-vous pas une fois l'événement terminé?

<input type="button" id="xx" onclick="checkEnableSubmit('true');yourFunction();">

<script type="text/javascript">

function checkEnableSubmit(status) {  
  document.getElementById("xx").disabled = status;
}

function yourFunction(){

//add your functionality

checkEnableSubmit('false');
}

</script>

Bonne codage !!!

2
Ravia

Quelques ajouts à la réponse de JoshRiver selon mon cas;

var functionCallbacks = [];
    var functionLock = false;
    var getData = function (url, callback) {
                   if (functionLock) {
                        functionCallbacks.Push(callback);
                   } else {
                       functionLock = true;
                       functionCallbacks.Push(callback);
                        $.getJSON(url, function (data) {
                            while (functionCallbacks.length) {
                                var thisCallback = functionCallbacks.pop();
                                thisCallback(data);
                            }
                            functionLock = false;
                        });
                    }
                };

// Usage
getData("api/orders",function(data){
    barChart(data);
});
getData("api/orders",function(data){
  lineChart(data);
});

Il n'y aura qu'un seul appel d'API et ces deux fonctions consommeront le même résultat.

0
Kadir Can