0

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 https://www.back4app.com but using it as the backend of the application. This service is base on Parse 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)

Here is the code of a service that call the API and return a Promise with the countries (paginate)

    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 => {
      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 "search field2"
    }
    query.include('continent');
    return query;
  }

  public fetchCountriesFromApiParser(skip = 0, limit = 10, order = 'code', searchName: string) {
    return new Promise<ICountry[]>((resolve, reject) => {
      const query = this.getCountriesQuery(skip, limit, order, searchName);
      query.find().then(results => {
        Promise.all(results.map(country => this.transformCountry(country)))
          .then(res => resolve(res));
      }, error => {
        reject(error);
      });
    });
  }

  private transformCountry(country: any) {
    return country.get('languages')
      .query()
      .find()
      .then(async language => {
        return await Promise.all(language.map(lang => lang.get('name')));
      })
      .then(async languages => {
        return { languages, timezone: await country.get('timezones').query().find() };
      })
      .then(async ({ languages, timezone }) => {
        return { languages, timezone, provinces: await country.get('provinces').query().find() };
      }).then(async ({ languages, timezone, provinces }) => {
        return { languages, timezone, provinces: await this.transformProvince(provinces).then() };
      }).then(({ languages, timezone, provinces }) => {
        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 => 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 => {
      return province.get('cities').query().find().then(async city => {
        return await Promise.all(city.map(c => 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 => {
        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);
      });
    }));
  }

This function is calling in a vuejs component (could be in other framework)

public fetchCountriesFromApi() {
    this.isFetching = true;
    // skip = 0, limit = 10
    this.countryService()
      .fetchCountriesFromApiParser(this.queryCount, this.itemsPerPage, this.sort, this.search)
      .then(res => {
        this.countries = res;
        this.isFetching = false;
      })
      .catch(error => {
        console.log(error);
        this.isFetching = false;
      });
  }

The result is as follows the table of countries

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

How can I improve and optimize my code for work correctly? Thanks for your help I hope you can help me cracks

Yuniel Acosta
  • 31
  • 1
  • 10
  • Not a lot to be done except: (1) purge the [explicit promise construction antipattern](https://stackoverflow.com/q/23803743/3478010) (2) (if possible) combine `country.get('languages').query().find()` and `country.get('timezones').query().find()` into a single query. (3) hard to see why `language.map(lang => ...)` needs to be wrapped in `Promise.all()` and awaited. Surely it's just the synchronous operation `let languages = language.map(lang => ...)`? – Roamer-1888 Aug 10 '20 at 01:30
  • the two calls are necessary because the api is conformed that way. Language and timezone are relations that are extracted in this way. – Yuniel Acosta Aug 10 '20 at 01:41
  • OK, then scrub (2) and concentrate on (1) and (3), though I expect the performance advantage will be absolutely minimal. – Roamer-1888 Aug 10 '20 at 01:56
  • @Roamer-1888 i edited the question with my previous code, this code has the same issue, ANY idea how to fix it – Yuniel Acosta Aug 10 '20 at 02:08
  • 1
    avoid using `.then` with async-await. – Daniel A. White Aug 10 '20 at 02:20
  • All the async logic looks good. I can't spot anything that would cause it to fail. – Roamer-1888 Aug 10 '20 at 02:21

0 Answers0