34 votes

Sécurité des discussions en Javascript?

J'ai un appel de fonction save(), cette fonction regroupe toutes les entrées sur la page, et effectue un appel AJAX vers le serveur à sauvegarder l'état de travail de l'utilisateur.

save() est actuellement appelée lorsque l'utilisateur clique sur le bouton enregistrer, ou effectue une autre action, qui exige que nous avons le plus de l'état actuel sur le serveur (générer un document à partir de la page par exemple).

Je m'ajoute à la capacité d'auto-enregistrer le travail de l'utilisateur chaque tellement souvent. Je tiens tout d'abord à empêcher la sauvegarde automatique et généré par les Utilisateurs d'enregistrer de s'exécuter en même temps. Nous avons donc le code suivant (je suis de coupe plus du code et ce n'est pas un rapport de 1:1, mais devrait être suffisant pour se faire une idée de l'échelle):

var isSaving=false;
var timeoutId;
var timeoutInterval=300000;
function save(showMsg)
{
  //Don't save if we are already saving.
  if (isSaving)
  { 
     return;
  }
  isSaving=true;
  //disables the autoSave timer so if we are saving via some other method
  //we won't kick off the timer.
  disableAutoSave();

  if (showMsg) { //show a saving popup}
  params=CollectParams();
  PerformCallBack(params,endSave,endSaveError);

}
function endSave()
{  
    isSaving=false;
    //hides popup if it's visible

    //Turns auto saving back on so we save x milliseconds after the last save.
    enableAutoSave();

} 
function endSaveError()
{
   alert("Ooops");
   endSave();
}
function enableAutoSave()
{
    timeoutId=setTimeOut(function(){save(false);},timeoutInterval);
}
function disableAutoSave()
{
    cancelTimeOut(timeoutId);
}

Ma question est de savoir si ce code est sûr? Faire les principaux navigateurs ne permettent qu'un seul thread à exécuter à un moment?

Une pensée que j'ai eu est qu'il serait pire pour l'utilisateur de cliquer sur enregistrer et n'obtenez pas de réponse, parce que nous sommes l'enregistrement automatique (Et je sais comment modifier le code pour gérer cette). Quelqu'un voit d'autres questions ici?

44voto

Jonathon Faust Points 7543

JavaScript dans les navigateurs est mono-thread. Vous ne jamais être en une seule fonction à n'importe quel point dans le temps. Fonctions complètes avant la prochaine est entré. Vous pouvez compter sur ce problème, donc si vous êtes dans votre save() fonction, vous n'aurez plus jamais la saisir à nouveau jusqu'à ce que l'on a fini.

Là où cela devient parfois confus (et reste encore vrai), c'est quand vous avez asynchrone des requêtes du serveur (ou setTimeouts ou setIntervals), car alors il se sent comme vos fonctions sont entrelacés. Ils ne sont pas.

Dans votre cas, tandis que les deux save() des appels ne se chevauchent pas les uns les autres, votre auto-save et utilisateur de sauvegarder pourrait se produire dos-à-dos.

Si vous voulez juste un sauve arriver au moins toutes les x secondes, vous pouvez faire un setInterval sur votre fonction de sauvegarde et de l'oublier. Je ne vois pas le besoin pour l' isSaving drapeau.

Je pense que votre code peut être simplifié beaucoup de choses:

var intervalTime = 300000;
var intervalId = setInterval("save('my message')", intervalTime);
function save(showMsg)
{
  if (showMsg) { //show a saving popup}
  params=CollectParams();
  PerformCallBack(params, endSave, endSaveError);

  // You could even reset your interval now that you know we just saved.
  // Of course, you'll need to know it was a successful save.
  // Doing this will prevent the user clicking save only to have another
  // save bump them in the face right away because an interval comes up.
  clearInterval(intervalId);
  intervalId = setInterval("save('my message')", intervalTime);
}

function endSave()
{
    // no need for this method
    alert("I'm done saving!");
}

function endSaveError()
{
   alert("Ooops");
   endSave();
}

7voto

Freyday Points 1002

Tous les principaux navigateurs ne prennent en charge qu'un seul fil javascript (sauf si vous utilisez des travailleurs Web ) sur une page.

Les demandes XHR peuvent cependant être asynchrones. Mais tant que vous désactivez la possibilité de sauvegarder jusqu'à la demande actuelle de sauvegarde des retours, tout devrait bien se dérouler.

Ma seule suggestion est de vous assurer d'indiquer d'une manière ou d'une autre à l'utilisateur quand une sauvegarde automatique a lieu (désactivez le bouton de sauvegarde, etc.).

2voto

Jeff Sternal Points 30147

L'exécution de javascript en un seul thread est actuellement effectuée par tous les principaux navigateurs (n'utilisez pas de travailleurs Web, car quelques navigateurs prennent en charge cette technique!). Cette approche est donc sécurisée.

Pour de nombreuses références, voir JavaScript est-il multithread ?

2voto

David Murdoch Points 28521

Cela me semble en sécurité. Javascript est à thread unique (sauf si vous utilisez des webworkers)

Ce n'est pas tout à fait sur le sujet, mais cet article de John Resig couvre les threads et les minuteries javascript: http://ejohn.org/blog/how-javascript-timers-work/

1voto

Bob Points 4773

Je pense que la façon dont vous êtes à la manutention, il est mieux pour votre situation. En utilisant le drapeau que vous êtes, à garantir que les appels asynchrones ne sont pas superposées. J'ai eu à traiter avec des appels asynchrones au serveur en tant que bien et aussi utilisé une sorte de drapeau pour éviter tout chevauchement.

Comme d'autres l'ont déjà souligné JavaScript est mono-thread, mais des appels asynchrones peut être difficile si vous vous attendez à avoir des choses à dire la même chose ou ne pas arriver pendant le voyage aller-retour vers le serveur.

Une chose, cependant, c'est que je ne pense pas que vous avez réellement besoin de désactiver l'enregistrement automatique. Si l'auto-save essaie de se produire lorsqu'un utilisateur est l'enregistrement puis la méthode save renvoie simplement et rien ne se passera. D'autre part, vous êtes inutilement la désactivation et la réactivation de la sauvegarde automatique à chaque fois que l'enregistrement automatique est activé. Je vous recommande de changer de setInterval et puis l'oublier.

Aussi, je suis un acharné pour minimiser les variables globales. Je serais probablement restructurer le code comme ceci:

var saveWork = (function() {
  var isSaving=false;
  var timeoutId;
  var timeoutInterval=300000;
  function endSave() {  
      isSaving=false;
      //hides popup if it's visible
  }
  function endSaveError() {
     alert("Ooops");
     endSave();
  }
  function _save(showMsg) {
    //Don't save if we are already saving.
    if (isSaving)
    { 
     return;
    }
    isSaving=true;

    if (showMsg) { //show a saving popup}
    params=CollectParams();
    PerformCallBack(params,endSave,endSaveError);
  }
  return {
    save: function(showMsg) { _save(showMsg); },
    enableAutoSave: function() {
      timeoutId=setInterval(function(){_save(false);},timeoutInterval);
    },
    disableAutoSave: function() {
      cancelTimeOut(timeoutId);
    }
  };
})();

Vous n'avez pas à refactoriser le code comme ça, bien sûr, mais comme je l'ai dit, je tiens à minimiser globals. La chose importante est que le tout devrait fonctionner sans la désactivation et la réactivation de l'enregistrement automatique chaque fois que vous enregistrez.

Edit: Oublié dû créer un privé de la fonction de sauvegarde pour être en mesure de référence de enableAutoSave

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X