6
votes

Comment se déplacer sur ce problème asynchrone mongodb / nœud?

J'ai le code suivant:

// Retrieve
var MongoClient = require("mongodb").MongoClient;
var accounts = null;
var characters = null;

// Connect to the db
MongoClient.connect("mongodb://localhost:27017/bq", function(err, db) {
   if(err) { return console.dir(err); }

    db.createCollection('accounts', function(err, collection) {
        if(err) { return console.dir(err); }
        else { accounts = collection; }

        createAccount("bob","bob");
        createAccount("bob","bob");
        createAccount("bob","bob");
        createAccount("bob","bob");
    });
});


function createAccount(email, password)
{
    accounts.findOne({"email":email}, function(err, item) {
        if(err) { console.dir(err); }
        else {
            if(item === null) {
                accounts.insert({"email":email, "password":password}, function(err, result) {
                    if(err) { console.dir(err); }
                    else { console.dir("Account " + email + " created."); }
                });
            }
            else {
                console.dir("Account already exists.")
            }

        }
    });
}


5 commentaires

Vous voulez donc que les 2nd, 3ème et 4e inserts échouent?


Oui, parce que le compte devrait déjà exister (mais pas encore).


La meilleure pratique consiste à ajouter un index unique sur e-mail , puis à gérer l'erreur insérer s'il y a une dupe comme une autre saveur du compte "existe déjà" erreur.


Cela ressemble à un bon moyen de le gérer.


Vous pouvez également essayer d'aborder un problème avec des promesses, voir: Stackoverflow.com/Questions/11912573/...


3 Réponses :


-1
votes

JavaScript est asynchrone. comptes.findone code> renvoie immédiatement, de sorte que toutes vos 4 déclarations sont exécutées ensemble.

what comptes.findone code> est, il dit que trouver un {" Email ": email} code> et lorsque vous le trouvez, exécutez la fonction qui se trouve dans le deuxième argument. Ensuite, il renvoie la fonction et continue à la prochaine déclaration CreeteAcount. En attendant, lorsque les résultats sont renvoyés à partir du disque dur (qui prend beaucoup plus de temps que l'exécution de ces déclarations), il entre dans la fonction, et comme il n'y a pas d'utilisateur, il en ajoute un. A du sens? P>

Mise à jour forte> C'est la bonne façon de le faire en JavaScript. P>

MongoClient.connect("mongodb://localhost:27017/bq", function(err, db) {
   if(err) { return console.dir(err); }

    db.createCollection('accounts', function(err, collection) {
        if(err) { return console.dir(err); }
        else { accounts = collection; }

        createAccount("bob","bob", function() {
            createAccount("bob","bob", function() {
                createAccount("bob","bob", function() {
                    createAccount("bob","bob", function() {
                     });
                });
            });
        });
    });
});


function createAccount(email, password, fn)
{
    accounts.findOne({"email":email}, function(err, item) {
        if(err) { console.dir(err); }
        else {
            if(item === null) {
                accounts.insert({"email":email, "password":password}, function(err, result) {
                    if(err) { console.dir(err); }
                    else { console.dir("Account " + email + " created."); }
                    fn();
                });
            }
            else {
                console.dir("Account already exists.")
                fn();
            }

        }
    });
}


3 commentaires

Je comprends pourquoi cela se passe, ce que je veux savoir, c'est ce que la meilleure façon de travailler autour de cela est.


J'ai ajouté le code ci-dessus pour montrer quelle bonne façon de le faire en JavaScript. Ou, vous pouvez utiliser la bibliothèque d'étape github.com/createix/step


Je suis enclin à perdre cette réponse sur la base de la mise à jour indiquant: "C'est la bonne façon de le faire en JavaScript". Tout d'abord, à propos de ASYNC Utilisez dans Node.js, pas JavaScript, il existe rarement une façon «droite» de faire quoi que ce soit dans le code. Espérons que tout développeur rationnel reconnaîtra que les rappels imbriqués dans ce scénario ne seront pas à l'échelle et ne sont pas une solution idéale ici. Je serais d'accord avec cette citation: "Cependant, plus que quelques niveaux de nidification devraient être un code de code - le temps de penser à ce que vous pouvez abstraire dans de petits modules séparés." Via book.mixu.net/node/ch7.html



0
votes

Ajoutez une contrainte unique sur le courrier électronique et vous n'aurez plus à vérifier si l'utilisateur existe plus!


0 commentaires

10
votes

Certaines langues fournissent une construction de langue spéciale pour faire face à ce problème. Par exemple, c # a async / attendre des mots-clés qui vous permettent d'écrire le code comme si vous appeliez des API synchrones.

JavaScript ne doit pas et vous devez chaîner les appels CreeACECCount avec rappels.

Certaines personnes ont développé des bibliothèques pouvant vous aider à organiser ce code. Par exemple async , étape , promesses et q < / a>

Vous pouvez également utiliser le Fibres bibliothèque, une bibliothèque indigène qui étend le temps d'exécution JavaScript avec des fibres / des coroutines.

et certaines personnes ont étendu la langue avec des constructions similaires à async / attendre : Streamline.js , ICEDCOffeScript ou wind.js . Par exemple, streamline.js (je suis l'auteur, donc je suis évidemment biaisé) utilise _ comme un espace réservé de rappel spécial et vous permet d'écrire votre exemple comme: xxx < / pré>

et, enfin mais non le moindre, de nouvelles fonctionnalités linguistiques telles que générateurs et Les fonctions différées sont en cours de discussion pour les futures versions de JavaScript (les générateurs sont très susceptibles d'atterrir en ES6, Les fonctions différées semblent être un peu calquées).

Vous avez donc de nombreuses options:

  • Stick to Callbacks
  • Utilisez une bibliothèque d'assistance
  • Utilisez l'extension d'exécution des fibres
  • Utilisez une extension de langue
  • Attendez ES6

2 commentaires

Une autre option à mentionner est Tamejs , qui est par les mêmes développeurs que ICEDCOffeScript - en fait, c'est le Version originale qui fonctionne dans un fichier JSL. Mais pour une raison quelconque, il génère deux fois plus de code (bien que autour du même nombre de fonctions) que Streamline.js, donc je recommanderais Streamline.js. En outre, Streamline.js vous permet de gérer des erreurs plus naturellement avec une option d'essai / attraper et d'une option de fibres qui le rend plus rapide.


Il convient également de noter que Streamline.js peut également être utilisé avec CoffeScript également (en appliquant la diffusion de Streamline.js après la transformation CoffeScript; plus de détails dans les docs).