-2

I need to build up map_of_uuid_ids_and_field_names_to_an_array_of_field_values.

I need to return this object after the loop is done looping. How?

Right now my code hangs on the inner part of this loop. I looked at it and realized that there is no "return" statement from the inner "then()" statement. But how I could I put a return statement there, when I need the code to loop? How can I return a Promise from this inner loop?

function get_map_of_uuid_ids_and_field_names_to_an_array_of_field_values(string_from_api_call, api_key_whose_name_should_match_the_name_of_a_database_field) {

    return new Promise(function(resolve, reject){

        var map_of_uuid_ids_and_field_names_to_an_array_of_field_values = {};
        sanitized_string_from_api_call = database_queries.sanitize_string(string_from_api_call);


        // 2017-07-10 -- this fixes:
        // TypeError: Cannot read property 'split' of null,   at get_map_of_uuid_ids_and_field_names_to_an_array_of_field_values (/home/ec2-user/daemons/deduplication_api/v9/dupe-res/actions.js:456:82)
        if (sanitized_string_from_api_call) {

            var array_of_words_from_string_from_api_call = sanitized_string_from_api_call.split(/\s+/);

            for (var k in array_of_words_from_string_from_api_call) {
                var word = array_of_words_from_string_from_api_call[k];

                // 2017-02-27 -- for the sake of performance, we skip over any string of 2 letters or less.
                // This means headquarters_country_code and headquarters_state_code need special handling.
                if (word.length > 2) {

                    return database_queries.get_map_of_type_of_profile_and_profile_id_pointing_to_document(word)
                        .then(function(map_of_type_of_profile_and_profile_id_pointing_to_document) {

                            if (map_of_type_of_profile_and_profile_id_pointing_to_document) {

                                map_of_uuid_ids_and_field_names_to_an_array_of_field_values = merge_objects(map_of_uuid_ids_and_field_names_to_an_array_of_field_values, transform_map_of_profile_type_and_profile_id_to_map_of_uuid_to_documents(map_of_type_of_profile_and_profile_id_pointing_to_document));

                            }
                        });
                }   
            }

        } else {
            console.log("the string value was null when api_key_whose_name_should_match_the_name_of_a_database_field was : " + api_key_whose_name_should_match_the_name_of_a_database_field); 
        }

        return map_of_uuid_ids_and_field_names_to_an_array_of_field_values;
    });
}
LRK9
  • 321
  • 2
  • 4
  • 15
  • 4
    What's with the long names exactly?! – Vandesh Jul 31 '17 at 16:39
  • If it’s async you can’t really return. – Charlie Fish Jul 31 '17 at 16:39
  • This is a funny question :) – Arpit Solanki Jul 31 '17 at 16:43
  • 1
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Tomalak Jul 31 '17 at 16:43
  • 2
    Also, you should re-evaluate your naming strategy. Being explicit about variable names is good, but this is crossing the line. – Tomalak Jul 31 '17 at 16:44
  • @Vandesh -- are these long variable names? In Java this would be written as "Map> field_values = new Map>();" which is about the same length. Since Javascript is dynamic, we use the name to carry the type information, though we are lucky that we don't have to go through all of the ceremony that Java requires of us. – LRK9 Aug 07 '17 at 05:21
  • In the above example of Java, the variable name is not long. The type again, is not too long I think and both these will be highlighted differently in an editor / IDE. It's still readable. And if you're keen on giving importance to Type in Javascript, then you should consider using Typescript, which is a superset of Javascript, and gives you much more control over the typing system. These names are not readable IMHO. – Vandesh Aug 08 '17 at 11:49

1 Answers1

2

First off, you can't directly return a result from a function that uses asynchronous operations to get the result. You can return a promise that (when resolved) will make the result available.

Second, anytime you want to call some async operation that returns a promise in a loop and you want to know when all the async operations started in the loop are done, the usual technique is to accumulate the promises in an array and use Promise.all() to tell you when they are all complete.

Third, your super long variable names make your code extremely difficult to read. I don't know if you just did this for the purpose of your question or if you generally code this way, but I find the names are so long that they obscure the flow and reading of the code. I applaud meaningful variable names, but this has gone so far that way that it wrecks the readability of the code and I can't imagine having to type all these just to work on the code.

So, after making the variable names more readable (to me) and applying the techniques above, here's a simplified version of your code:

function get_idMap(str, apiKey) {
    let promises = [];
    let idMap = {};
    let santizedString = database_queries.sanitize_string(str);
    if (santizedString) {
        santizedString.split(/\s+/).forEach(function(word) {
        // 2017-02-27 -- for the sake of performance, we skip over any string of 2 letters or less.
        // This means headquarters_country_code and headquarters_state_code need special handling.
        if (word.length > 2) {
            promises.push(database_queries.get_profileMap(word).then(function(profileMap) {
                if (profileMap) {
                    idMap = merge_objects(idMap, transformProfile(profileMap));
                }
            }));
        });
    } else {
        console.log("the string value was null when apiKey was : " + apiKey); 
    }
    return Promise.all(promises).then(function() {
        return idMap;
    });
}

And, since this returns a promise, you would use it like this:

get_idMap(someStr, yourKey).then(function(idMap) {
    // use the idMap here
}).catch(function(err) {
    // handle error here
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 1
    Why the downvote? Does this not teach how to solve the type of problem in the OP's code? If you provide downvote feedback, perhaps I could improve the answer. – jfriend00 Jul 31 '17 at 17:35
  • 2
    Your variable names probably aren't long enough. – Sterling Archer Jul 31 '17 at 18:00
  • Seriously. Why the multiple downvotes? What is wrong with this answer? – jfriend00 Jul 31 '17 at 18:18
  • Are these long variable names? In Java this would be written as "Map> field_values = new Map>();" which is about the same length. Since Javascript is dynamic, we use the name to carry the type information, though we are lucky that we don't have to go through all of the ceremony that Java requires of us. – LRK9 Aug 07 '17 at 05:23
  • 1
    @LRK9 - Meaningful variables names are good. Names so long, you can't follow the flow of the code or remember what to type without using copy/paste are going significantly too far. I'd guess that the majority of folks here would say these names are so long that they obscure, rather than help, people understand the code (that's my opinion). Also, there's a lot of superfluous information in many of these names that is not required to understand what the function does or how it works. And, some of this information belongs in a comment, not in every use of the variable. My opinion. – jfriend00 Aug 07 '17 at 05:48