Back

Explore Courses Blog Tutorials Interview Questions
0 votes
2 views
in Web Technology by (7k points)

I have a structure that would expose async methods. The async method calls return array structures that would inturn expose more async methods. I am creating another JSON object to store values obtained from this structure and because of this I need to be careful about keeping track of references in callbacks.

I would like a clean solution following these rules:

  1. The pattern should be repeatable for n levels of nesting.

  2. I need to use promise.all or some similar technique to determine when to resolve the enclosing routine.

  3. Not every element will necessarily involve making an async call. So in a nested promise.all I can't simply make assignments to my JSON array elements based on an index. Nevertheless, I do need to use something like a promise.all in the nested forEach to ensure that all property assignments have been made before resolving the enclosing routine.

  4. I am using the bluebird promise lib but this is not a requirement

This is what I have done so far:

var jsonItems = [];

 items.forEach(function(item)

{

 var jsonItem = {};

 jsonItem.name = item.name;

 item.getThings().then(function(things)

{

 // or Promise.all(allItemGetThingCalls, function(things){ 

things.forEach(function(thing, index){

 jsonItems[index].thingName = thing.name;

 if(thing.type === 'file'){

 thing.getFile().then(function(file){ //or promise.all?

 jsonItems[index].filesize = file.getSize();

}}

1 Answer

0 votes
by (13.1k points)

Follow these rules:

  • Whenever you create a promise in a then, return it - any promise you don't return will not be waited for outside.

  • Whenever you create multiple promises, .all them - that way it waits for all the promises, and no error from any of them are silenced.

  • Whenever you nest then, you can typically return in the middle - then chains are usually at most 1 level deep.

  • Whenever you perform IO, it should be with a promise - either it should be in a promise or it should use a promise to signal its completion.

Follow these tips:

  • Mapping is better done with .map than with for/push - if you're mapping values with a function, the map lets you concisely express the notion of applying actions one by one and aggregating the results.

  • Concurrency is better than sequential execution if it's free - it's better to execute things concurrently and wait for the Promise.all than to execute things one after the other - each waiting before the next.  

Following the above rules and tips you can do something like this:

var items = [1, 2, 3, 4, 5];

var fn = function asyncMultiplyBy2(v){ // sample async action

    return new Promise(resolve => setTimeout(() => resolve(v * 2), 100));

};

// map over forEach since it returns

var actions = items.map(fn); // run the function over all items

// we now have a promises array and we want to wait for it

var results = Promise.all(actions); // pass array of promises

results.then(data => // or just .then(console.log)

    console.log(data) // [2, 4, 6, 8, 10]

);

// we can nest this of course, as I said, `then` chains:

var res2 = Promise.all([1, 2, 3, 4, 5].map(fn)).then(

    data => Promise.all(data.map(fn))

).then(function(data){

    // the next `then` is executed after the promise has returned from the previous

    // `then` fulfilled, in this case it's an aggregate promise because of 

    // the `.all` 

    return Promise.all(data.map(fn));

}).then(function(data){

    // just for good measure

    return Promise.all(data.map(fn));

});

// now to get the results:

res2.then(function(data){

    console.log(data); // [16, 32, 48, 64, 80]

});

Check out the NodeJS interview questions from Intellipaat.

Related questions

Welcome to Intellipaat Community. Get your technical queries answered by top developers!

30.5k questions

32.5k answers

500 comments

108k users

Browse Categories

...