2015-12-10 24 views
5

Ich habe ein dict wie folgt aus:NodeJS parallel mit Versprechen

{go: ['went', 'run'], love: ['passion', 'like']}

Der Wert eines Schlüssels seine Synonyme ist. Und 'getSynonymWords (Wort)' ist eine asynchrone Funktion, die eine Verheißung zurückgibt, deren Wert eine Liste von Synonymen ist, die dem übergebenen Parameter entsprechen. Wie kann ich Schleife durch das Objekt ein anderes Objekt rekursiv wie folgt zu erhalten:

{went: [], run: [], passion: [], like: []} 

Das ist mein Stück Code:

function getRelatedWords(dict) { 
    return new Promise(function(resolve) { 
    var newDict = {}; 
    for(var key in dict){ 
     if (dict.hasOwnProperty(key)) { 
     var synonyms = dict[key]; 
     Promise.map(synonyms, function (synonym) { 
      return getSynonymWords(synonym).then(function (synonyms) { 
      newDict[synonym] = synonyms; 
      return newDict; 
      }); 
     }).then(function() { 
      resolve(newDict); 
     }); 
     } 
    } 
    }); 
} 

Es ist falsch, da einige Aufgaben nicht fertig sind, aber ich don‘ Ich weiß, wie man Aufgaben parallel verschachtelt mit Versprechungen ausführt. Ich benutze die Bluebird-Bibliothek. Kannst du mir helfen?

+1

Javascript ist single-threaded - so gibt es keine 'parallel' –

+0

Vielleicht ist es ein Teil von Bluebird, ich weiß es nicht, aber Promise.map ist keine Funktion in Vanille JS. –

+0

@BrandonNozakiMiller - Bluebird hat viel Zucker –

Antwort

5

Erstens, vermeiden Sie explizite Konstruktion. Jetzt, wo wir damit fertig sind, können wir das ohne Verschachtelung und 4 Zeilen Code machen, indem wir zuerst alle Wörter bekommen, dann alle Synonyme holen und sie dann in ein Wörterbuch zurückfalten.

function getRelatedWords(dict) { 
    // first we get all the synonyms 
    var synonyms = Object.keys(dict).map(x => dict[x]).reduce((p, c) => p.concat(c), []); 
    // second we get all the synonyms for each word with the word itself 
    var withSynonyms = Promise.map(synonyms, s => Promise.all([s, getSynonymWords(s)])); 
    // then we fold it back to an object with Promise.reduce 
    var asDict = withSynonyms.reduce((p, c) => p[c[0]] = c[1]), {}); 
    // and return it 
    return asDict; 
} 

Wenn wir als „clever“ wollten wir ein Motto entscheiden kann, werde ich ES2016 verwenden hier für Spaß:

let {entries} = Object; 
let {reduce, all} = Promise; 
const getRelatedWords = dict => reduce(entries(dict), (p, c) => p.concat(c), []).map(s => [s, getSynonymWords(s)]).map(all).reduce((p, [s, syns]) => p[s] = syns, {}); 

Die bessere Lösung btw ist wahrscheinlich etwas zu verwenden, wie Wordnet, mit dem Sie die Entfernung festlegen und einen einzelnen Anruf tätigen können.

+1

Vielen Dank. Dein Code ist so schön. Aber ich habe eine Frage, wie man sicherstellen kann, dass alle 'getSynonymWörter' ausgeführt werden, bevor 'asDict' erhalten wird. – nguyenngoc101

+0

@ nguyenngoc101 Ich benutze 'Promise.reduce' und nicht' reduce', was auf die Werte wartet, wenn sie versprechen (das ist eine Bluebird-Methode). Ich werde es bearbeiten, um die nicht-statische Version zu verwenden, da das etwas netter ist. –