Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodejs parallel with promise

I have a dict like this:

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

The value of a key is its synonyms. And 'getSynonymWords(word)' is a async function that returns a promise in which Its value is a list of synonym words corresponding with the parameter passed. How can I loop through the object to get another object recursively like this:

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

This is my piece of 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);
        }); 
      }   
    }   
  }); 
}

It is incorrect because some tasks are not finished, But I don't know how to run tasks parallel nested with promises. I'm using Bluebird library. Could you help me?

like image 695
nguyenngoc101 Avatar asked Dec 10 '15 09:12

nguyenngoc101


People also ask

Does Promise run in parallel?

So, yes, the V8 implementation if you will. Promises cannot "be executed". They start their task when they are being created - they represent the results only - and you are executing everything in parallel even before passing them to Promise.

Is js Promise all parallel?

As you can see, Promise. all executes code concurrently, but what is parallel execution? JavaScript is single-threaded and can only perform a single chunk of work at a time, so parallel execution is not possible with JavaScript, except for some circumstances such as web workers.

How do you do multiple promises in parallel?

So, to run all these APIs in parallel, we can use Promise. all() like so. As you can tell, now we're running all the three APIs in parallel through Promise. all() through a single await .

How Promise all works parallel?

The Promise.all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will fulfill when all of the input's promises have fulfilled, or if the input iterable contains no promises.


1 Answers

First of all, avoid explicit construction. Now that we're over that - we can do this with no nesting and 4 lines of code by first getting all the words, then getting all the synonyms, then folding them back to a dictionary.

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; 
}

If we wanted to be "clever" we can opt to a one liner, I'm going to use ES2016 here for fun:

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, {});

The better solution btw is probably to use something like wordnet that lets you specify the distance and make a single call.

like image 60
Benjamin Gruenbaum Avatar answered Sep 24 '22 00:09

Benjamin Gruenbaum