'Javascript closure with async ajax data initializer

I'm stuck trying to figure out how to create a closure API with an ajax data initializer.

My goal is to initialize a countries object (hash of hashes of country information) via an async ajax call (this initialization happens once on page load), then this data is encapsulated in a closure so that only two APIs are visible: one getCountryInfo() that just gets country's info and countryAutoComplete() that is an api for jquery-ui's autocomplete functionality.

Question: I have the two bits of code, but I do not know how to perform the ajax request and have its data available for the closure and be able to return the userdb API to the application. I can do any 2/3, but I'm not sure how to tie it all together.

I have javascript and jquery at my disposal.

Here are the two bits of code. (This is a simplified example, cut down for this question. I've tried to avoid syntax errors in this excerpt, but understand this is not the actual code.)

// populate the data initially
timestamp = localStorage.getItem('all_countries_time') || 0;
$.getJSON(
    "/api",
    {
        item: 'countries',
        timestamp: timestamp
    },
    function(data)
    {
        // !! I need this data set before I can run the code below
        if (data.timestamp != '0')
        {
            localStorage.setItem('all_countries_time', data.timestamp);
            localStorage.setItem('all_countries', JSON.stringify(data.countries));
        }
    }
);

And

// Create the API in a closure

var countrydb = (function() {
    let countries = JSON.parse(localStorage.getItem('all_countries'));

    // ! I don't think I can return this API from a response() or when().then() clause. But I could be wrong.
    return {
        getCountryInfo: function(country)
        {
            return countries[country]
        },
        countryAutoComplete: function(prefix, callback)
        {
            let cmatch = [];
            for (const [name, cinfo] of Object.entries(countries)) {
                if (name.startsWith(prefix) || cinfo.intlcode.startsWith(prefix) ) {
                    cmatch.push(userinfo);
                }
            }
            callback(cmatch);

        }
    };
});

let cdb = countrydb();
let canada = cdb.getCountryInfo('Canada');
$("#countries_select").autocomplete(source: cdb.countryAutoComplete);


Update I never did find a solution. In the end I have two globals countries and countries_initialized. Setups of getCountryInfo() and countryAutoComplete() functions come after a successful poll-and timer for countries_initialized being set.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source