title: How can I optimize multiple nested calls that return promises in javascript / typescript?
body: <p>I need help to optimize my code, it works well in some occasions but in others it lacks results when consulting an internet service.
  The service is <a href="https://www.back4app.com/database/back4app/list-of-all-continents-countries-cities/get-started/javascript/rest-api/fetch" rel="nofollow noreferrer">https://www.back4app.com</a> but using it as the backend of the application. This service is base on <a href="https://docs.parseplatform.org/" rel="nofollow noreferrer">Parse</a>
  My problem consists of wanting to bring all the data of the countries in a single call to the API (both the common data and their relations) What happens is that the calls to the apis are being made within a map to transform the data and return an arrangement with all the countries and their relationships, say languages, timezone, continent and provinces (the latter I have not done because I have problems with the previous ones that seem simpler)</p>
  <p>Here is the code of a service that call the API and return a Promise with the countries (paginate)</p>
  <pre><code>    private getCountriesQuery(skip: number, limit: number, order: string, searchName: string) {
      const Continentscountriescities_Country = Parse.Object.extend('Continentscountriescities_Country');
      const query = new Parse.Query(Continentscountriescities_Country);
      query.limit(limit); // limit to at most 10 results
      query.skip(skip); // skip the first x results
      const orders: string[] = order.split(',');
      orders.map(o =&gt; {
        if (o.startsWith('-')) {
          query.descending(o.replace('-', '')); // Sorts the results in descending order by the x field
        } else {
          query.ascending(o); // Sorts the results in ascending order by field x
        }
      });
      if (searchName) {
        query.skip(0);
        query.limit(50);
        query.startsWith('name', searchName); // name starts with &quot;search field2&quot;
      }
      query.include('continent');
      return query;
    }
  
    public fetchCountriesFromApiParser(skip = 0, limit = 10, order = 'code', searchName: string) {
      return new Promise&lt;ICountry[]&gt;((resolve, reject) =&gt; {
        const query = this.getCountriesQuery(skip, limit, order, searchName);
        query.find().then(results =&gt; {
          Promise.all(results.map(country =&gt; this.transformCountry(country)))
            .then(res =&gt; resolve(res));
        }, error =&gt; {
          reject(error);
        });
      });
    }
  
    private transformCountry(country: any) {
      return country.get('languages')
        .query()
        .find()
        .then(async language =&gt; {
          return await Promise.all(language.map(lang =&gt; lang.get('name')));
        })
        .then(async languages =&gt; {
          return { languages, timezone: await country.get('timezones').query().find() };
        })
        .then(async ({ languages, timezone }) =&gt; {
          return { languages, timezone, provinces: await country.get('provinces').query().find() };
        }).then(async ({ languages, timezone, provinces }) =&gt; {
          return { languages, timezone, provinces: await this.transformProvince(provinces).then() };
        }).then(({ languages, timezone, provinces }) =&gt; {
          return new Country(
            undefined,
            country.id,
            country.get('name'),
            country.get('code'),
            country.get('native'),
            country.get('phone'),
            country.get('capital'),
            country.get('currency'),
            country.get('emoji'),
            country.get('emojiU'),
            country.get('geonameid'),
            languages.toString(),
            JSON.stringify(timezone.map(tz =&gt; tz.get('TimeZone'))),
            country.get('continent').get('name'),
            country.get('createdAt'),
            country.get('updatedAt'),
            false,
            provinces);
        });
    }
  
    private transformProvince(provinces: any) {
      return Promise.all(provinces.map(province =&gt; {
        return province.get('cities').query().find().then(async city =&gt; {
          return await Promise.all(city.map(c =&gt; new City(undefined, c.id, c.get('cityId'), c.get('name'), c.get('altName'), c.get('location'), c.get('location'),
            c.get('adminCode'), c.get('population'), c.createdAt, c.updatedAt, false, province)));
        }).then(cities =&gt; {
          return new Province(undefined, province.id, province.get('Country_Code'), province.get('Subdivision_Code'), province.get('Subdivision_Name'), province.get('Subdivion_Type'),
            province.createdAt, province.updatedAt, false, cities);
        });
      }));
    }
  </code></pre>
  <p>This function is calling in a vuejs component (could be in other framework)</p>
  <pre><code>public fetchCountriesFromApi() {
      this.isFetching = true;
      // skip = 0, limit = 10
      this.countryService()
        .fetchCountriesFromApiParser(this.queryCount, this.itemsPerPage, this.sort, this.search)
        .then(res =&gt; {
          this.countries = res;
          this.isFetching = false;
        })
        .catch(error =&gt; {
          console.log(error);
          this.isFetching = false;
        });
    }
  </code></pre>
  <p>The result is as follows
  <a href="https://i.stack.imgur.com/hq8Ag.png" rel="nofollow noreferrer">the table of countries</a></p>
  <p>Note the Bolivia and Benin countries with blank languages. This happens randomly with other countries and I suspect it is because some promise does not execute on time</p>
  <p>How can I improve and optimize my code for work correctly?
  Thanks for your help I hope you can help me cracks</p>