2017-03-20 9 views
1

Ich habe eine Frage bezüglich des Verhaltens von rekursiven asynchronen Anforderungen in Node.js.Probleme mit der asynchronen Rekursion in Node.js

Die folgende Funktion dient dazu, Suchergebnisse von MongoDB zurückzugeben. Wenn die anfänglichen Suchergebnisse leer sind, teile ich den Text in einzelne Wörter auf und versuche dann rekursiv fetchResult (...) für jedes Wort, wobei das Objekt res als Parameter übergeben wird.

function fetchResult(text, res){ 
    var MongoClient = require('mongodb').MongoClient; 

    MongoClient.connect(mongoURL + "/search", function (err, db) { 

     if(err) throw err; 

     db.collection('results', function(err, collection) { 

      // search for match that "begins with" text 
      collection.findOne({'text':new RegExp('^' + text, 'i')}, function(err, items){ 

       var result = (items == null || items.result == null) ? "" : items; 

       if (result){ 
        res.send(result); 
       } 
       else { 
        // no result, so fire off individual word queries - if any spaces found 
        if (text.indexOf(' ') > -1){ 
         // split string into array 
         var textArray = text.split(" "); 

         // recursively process individual words 
         for (index = 0; index < textArray.length; index++) { 
          // ***** RACE CONDITION HERE? ***** 
          fetchResult(textArray[index], res); 
         } 
        } 
        else { 
         // just return empty result 
         res.send(result); 
        } 
       } 
      }); 
     }); 
    }); 
} 

Ich vermutete, könnte dies ein bisschen eine Race-Bedingung verursachen, als Verweis auf res auffächert asynchron, und dies wurde bestätigt, als ich den Code lief und beobachtet den folgenden Fehler:

Error: Can't set headers after they are sent. 
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11) 

Also meine Frage ist: Wie kann ich das gewünschte rekursive Verhalten der Ausführung einzelner String-Abfragen in Folge erreichen, nur zurückgeben, wenn wir das erste Ergebnis finden (oder am Ende des Prozesses, wenn die Suche überhaupt keine Ergebnisse zurückgegeben)?

+0

Studie über die Versprechen – Deep

Antwort

1

Ihr Code benötigt einige Refactoring.

Zuerst entfernen Sie den MongoClient.connect Anruf von der fetchResult Funktion. Sie können die Verbindung einmal herstellen und das Objekt db zur späteren Verwendung speichern.

Zweitens, mit Ihrem Ansatz geben Sie eine Antwort für jedes Wort in der Abfrage zurück. Ich denke nicht, dass ein rekursiver Aufruf der Weg ist, hier zu gehen.

Sie werden mehrere asynchrone Abfragen haben, wenn Ihre erste Abfrage fehlschlägt, und Sie irgendwie die Ergebnisse aggregieren müssen ... hier wird es schwierig. Ich bin mit Mongo nicht so vertraut, aber ich glaube, Sie können dies vermeiden, indem Sie eine Reihe von Ergebnissen mit find $in abrufen. Siehe this question, vielleicht hilft es.

+0

Danke, ich habe die Erstellung der Verbindung und Sammlung getrennt, so dass es jetzt wiederverwendbar ist. An welcher Stelle schließe ich nun die Verbindung? – HomerPlata

+0

Ich habe nicht das ganze Bild Ihres Codes, aber ich nehme an, Ihre FetchResult-Methode wird von einer Anfrage-Methode aufgerufen ... Sie könnten Ihre Verbindung dort verwalten. – mihai

+0

Was ist der tatsächliche Vorteil des Verschiebens des Verbindungserstellungscodes in die aufrufende Methode? – HomerPlata

Verwandte Themen