2012-03-26 2 views
0

J'ai récemment rencontré un bogue familier de javascript/jQuery et j'ai passé trop de temps à le déboguer. Ce dont j'ai besoin, c'est d'un chemin de débogage plus intelligent pour ce problème. En particulier, mon problème était que les entrées de l'utilisateur étaient censées provoquer un appel de base de données Mongo et les résultats ont été envoyés, après un peu de maths, aux sorties affichées. Mais les sorties affichées étaient follement fausses. Cependant, une fois que j'ai ajouté un point de rupture FireBug le problème est parti. À ce moment-là, je savais que j'avais un problème de timing, mais pas comment le résoudre.Comment déboguer les problèmes de synchronisation dans Javascript?

Voici les pièces relavant de code avant l'erreur:

handleDataCallBack : function(transport) { 
    var response = $.parseJSON(transport); 

    if(!hasErrors) { this.updatePage(response); } 
}, 

accessDatabase : function(){ 
    var params = { ... }; 
    DAL.lookupDatabaseInfo(this.handleCallBackOutputPanel, this, params); 
}, 

calculateValues: function() { 
    // some numerical values were updated on the page 
} 

onDomReady : function() { 
// ... 
    //bind drop-down select change events 
    $('#someDropDown').change(function() { 
     me.accessDatabase(); 
     me.calculateValues(); 
    }); 
} 

Pour résoudre le problème, tout ce que je devais faire était déplacer la méthode « calculateValues ​​» de la onDomReady dans l'appel retour:

handleDataCallBack : function(transport) { 
    var response = $.parseJSON(transport); 

    this.calculateValues(); 
    if(!hasErrors) { this.updatePage(response); } 
}, 

Le problème était que la base de données n'avait pas répondu avant le début des calculs. Bien sûr, c'est facile à repérer rétrospectivement. Mais quelles méthodes puis-je utiliser pour déboguer les problèmes de synchronisation asynchrone dans javascript/jQuery à l'avenir? Cela semble bien en dehors du contexte des outils IDE. Et FireBug n'a pas aidé. Existe-t-il des outils permettant de détecter les problèmes de développement Web asynchrones? Ou peut-être des méthodes éprouvées par le temps?

+0

donc en général, quel est le flux du programme? – Joseph

+0

En général, le flux du programme est qu'il y a une liste déroulante sur la page Web qui, une fois qu'un nouvel élément est sélectionné, effectue un appel de base de données. Cet appel renvoie ~ 20 flottants, et ces flottants sont utilisés dans la méthode 'calculateValues' pour afficher automatiquement 4 valeurs flottantes calculées sur la page. (La page a beaucoup plus de choses en cours, mais c'est la partie pertinente.) – theJollySin

+0

Certes, mon expérience Javascript est limitée, mais j'ai fait face à un problème similaire une fois. La solution était de le re-concevoir de telle sorte qu'il n'y ait pas de possibilité de problèmes de timing. Pour ce faire, définissez des signaux pour les événements terminés et les auditeurs pour ces signaux. J'ai utilisé le cadre de traitement des signaux plus général de MochiKit pour cela. – Keith

Répondre

2

Je suppose que votre problème est causé ici:

$('#someDropDown').change(function() { 
    me.accessDatabase(); 
    me.calculateValues(); 
}); 

cette question est que vos calculs sont faits juste après l'appel. voyant que l'appel de la base de données est asynchrone, calculer ne l'attend pas. Cependant, vous pouvez le faire en utilisant "callbacks". Je vois que vous essayez de l'appliquer et oui, c'est correct. cependant, je trouve cela plus élégant:

calculateValues: function() { 
    // some numerical values were updated on the page 
}, 

//since this is your general callback hander 
//you hand over the return data AND the callbackAfter 
handleDataCallBack: function(transport, callbackAfter) { 
    var response = $.parseJSON(transport); 

    //you may need to use apply, im lost in scoping here 
    callbackAfter(); 
    //or 
    callbackAfter.apply(scope); 

    if (!hasErrors) { 
     this.updatePage(response); 
    } 
}, 

accessDatabase: function(callbackAfter) { 
    var params = {}; 

    //pass callbackAfter to the function, 
    //after this is done, pass it to the handler 
    DAL.lookupDatabaseInfo(this.handleCallBackOutputPanel, this, params, callbackAfter); 
}, 

onDomReady: function() { 
    $('#someDropDown').change(function() { 
     me.accessDatabase(function() { 
      //send over what you want done after. 
      //we'll call it "callbackAfter" for easy tracing 
      me.calculateValues(); 
     }); 
    }); 
}​ 
+0

Merci pour votre contribution. Pour être honnête, je cherchais plus d'une technique de débogage que ce que vous avez posté. Mais ce que vous avez posté semble être une façon plus intelligente de faire les choses, alors je vais mettre en œuvre quelque chose de très similaire. C'est très pratique. Merci. – theJollySin

Questions connexes