2017-12-09 3 views
1

Das Problem ist wie folgt. Ich habe ein Array von Objekten wie so:Wie kann ich diese verschachtelte asynchrone Schleife verbessern?

let myObj = [ 
{'db1':['doc1','doc2','doc3']}, 
{'db2':['doc4','doc5']}, 
{'db3':['doc7','doc8','doc9','doc10']} 
] 

Beachten Sie, dass dies eine Datenstruktur, entschied ich mich für das Problem zu bedienen und kann geändert werden, wenn es die allgemeine Umsetzung verbessern. Die tatsächlichen db- und doc-IDs werden aus einer Textdatei gelesen, die wie folgt formatiert ist.

"db1","doc1" 
"db1","doc2" 
... 

Meine App wird synchron durch die Datenbankliste iterieren. Innerhalb jeder db-Iteration wird eine asynchrone Iteration der Dokumentliste stattfinden. Jedes Dokument wird abgerufen, verarbeitet und in der Datenbank gespeichert.

Also grundsätzlich bei jeder gegebenen Instanz: eine db, aber mehrere Dokumente.

Ich habe eine Arbeits Umsetzung der oben etwa so:

dbIterator: die synchrone äußeren Schleife THS iterieren. Der an docIterator übergebene Rückruf löst die nächste Iteration aus.

const dbIterator = function (x) { 
    if (x < myObj.length) { 
    let dbObj = myObj[x]; 
    let dbId = Object.keys(dbObj)[0]; 
    docIterator(dbId, dbObj[dbId],()=>merchantIterator(x+1)); 
    } else { 
    logger.info('All dbs processed'); 
    } 
}; 

docIterator: die asynchrone Schleife docs iterieren. Der Callback cb wird aufgerufen, nachdem alle Dokumente verarbeitet wurden. Dies geschieht über das docsProcessed und docsToBeProcessed Variablen verfolgt

const docIterator = function(dbId, docIds, cb){ 
    //create connection 
    targetConnection = //some config for connection to dbId 
    let docsProcessed = 0; 
    let docsToBeProcessed = docIds.length; 

    //asynchronous iteration of documents 
    docIds.forEach((docId)=>{ 
    getDocument(docId, targetConnection).then((doc)=>{ 
     //process document 
     processDoc(doc, targetConnection).then(()=>{ 
     //if processing is successful 
     if (++docsProcessed >= docsToBeProcessed) { 
      cb(); 
     } 
     }) 
     //if processing fails 
     .catch((e) => { 
     logger.error('error when processing document'); 
     if (++docsProcessed >= docsToBeProcessed) { 
      cb(); 
     } 
     }); 

    }).catch((e)=>{ 
     logger.error('error when retrieving document: '); 
     if (++docsProcessed >= docsToBeProcessed) { 
     cb(); 
     } 
    }); 
    }); 
}; 

processDoc: verwendet zu verarbeiten und ein individuelles Dokument zu speichern. Dies gibt ein Versprechen, das gelöst wird, wenn die Dokumentenverarbeitung, was wiederum Schritten erfolgt docsProcessed und bedingt (docsProcessed >= docsToBeProcessed) ruft den Anruf in docIterator

const processDoc = function(doc, targetConnection) { 

    return new Promise(function(resolve, reject) { 
    if(shouldThisDocBeProcessed(doc){ 
     let updatedDoc = logic(doc); 
     targetConnection.insert(updatedDoc, updatedDoc._id, 
     function (error, response) { 
      if (!error){ 
      logger.info('updated successfully'); 
      } else { 
      logger.error('error when saving doc'); 
      } 
      resolve(); 
     } 
    ); 
    } else { 
     resolve(); 
    } 
    }) 
}; 

zurückgegeben, wie erwartet Das funktioniert aber für mich diese Implementierung ist suboptimal und unordentlich. Ich bin mir ziemlich sicher, dass dies verbessert werden kann und vor allem eine Chance, Lösungen für synchrone und asynchrone Probleme besser zu verstehen und zu implementieren.

Ich bin offen für konstruktive Kritik. Wie kann das verbessert werden?

+0

Ein guter Platz für Codeüberprüfungen ist https://codereview.stackexchange.com/. Stimme für die Zeit und Mühe ab, die du für die Formulierung dieses Artikels aufgewendet hast, –

+0

Ist es "Docs" oder "DocIds"? – Bergi

+0

Da Sie mit Versprechen arbeiten: Verwenden Sie kein Callback-Argument in Ihrer 'docIterator'-Funktion. Gib ein Versprechen zurück! Außerdem müssen Sie nicht all diesen Prozess selbst zählen - verwenden Sie einfach "Promise.all". – Bergi

Antwort

0

Vielleicht so etwas?

Eine Beispielimplementierung der Drossel kann here gefunden werden.

//this should be available in both modules so you can filter 
const Fail = function(details){this.details=details;}; 
// docIterator(dbId,docIds) 
// .then(
// results =>{ 
//  const failedResults = results.filter(
//  result => (result&&result.constructor)===Failed 
// ); 
//  const successfullResults = results.filter(
//  result => (result&&result.constructor)!==Failed 
// ); 
// } 
//) 

const docIterator = function(dbId, docIds){ 
    //create connection 
    // targetConnection = //some config for connection to dbId 
    let docsProcessed = 0; 
    let docsToBeProcessed = docIds.length; 
    //asynchronous iteration of documents 
    docIds.map(
    docId => 
     new Promise(
     (resolve,reject) => 
      //if you use throttled you can do: 
      // max10(
      // ([docId,targetConnection])=> 
      //  getDocument(docId,targetConnection) 
      //)([docId, targetConnection]) 
      getDocument(docId, targetConnection) 
    ) 
     .then(
     doc => 
      //if this returns nothing then maybe you'd like to return the document 
      processDoc(doc, targetConnection) 
      .then(
      _ => doc 
     ) 
    ) 
     .catch(
     err => new fail([err,docId]) 
    ) 

) 
}; 
Verwandte Themen