How can I refactor for handling multiple proto generated service clients by eliminating double await and the DRY code? I'm having doubts about which is the best strategy to manage the many service clients in this web app.
&quot;Best&quot; in terms of a good compromise between user's device RAM and Javascript execution speed (main thread ops).
This is what I'm doing right now, this is the main file:

main.ts:

import type { PlayerServiceClient } from './player.client';
import type { TeamServiceClient } from './team.client';
import type { RefereeServiceClient } from './referee.client';
import type { FriendServiceClient } from './friend.client';
import type { PrizeServiceClient } from './prize.client';
import type { WinnerServiceClient } from './winner.client';
import type { CalendarServiceClient } from './calendar.client';

let playerService: PlayerServiceClient;
export const player = async (): Promise&lt;PlayerServiceClient&gt; =&gt;
    playerService ||
    ((playerService = new (await import('./player.client')).PlayerServiceClient()),
    playerService);

let teamService: TeamServiceClient;
export const getTeamService = (): TeamServiceClient =&gt;
    teamService ||
    ((teamService = new (await import('./team.client')).TeamServiceClient()),
  teamService);

let refereeService: RefereeServiceClient;
export const getRefereeService = (): RefereeServiceClient =&gt;
    refereeService ||
  ((refereeService = new (await import('./referee.client')).RefereeServiceClient()),
  refereeService);

let friendService: FriendServiceClient;
export const getFriendService = (): FriendServiceClient =&gt;
    friendService ||
  ((friendService = new (await import('./friend.client')).FriendServiceClient()),
  friendService);

let prizeService: PrizeServiceClient;
export const getPrizeService = (): PrizeServiceClient =&gt;
    prizeService ||
  ((prizeService = new (await import('./prize.client')).PrizeServiceClient()),
  prizeService);

let winnerService: WinnerServiceClient;
export const getWinnerService = (): WinnerServiceClient =&gt;
    winnerService ||
  ((winnerService = new (await import('./winner.client')).WinnerServiceClient()),
  winnerService);

let calendarService: CalendarServiceClient;
export const getCalendarService = (): CalendarServiceClient =&gt;
    calendarService ||
  ((calendarService = new (await import('./calendar.client')).CalendarServiceClient()),
  calendarService);

// and so on... a lot more...

As you can see there are many service clients.
I'm using this code because I thought it was better given my web app structure based on routes almost overlapping with client services:
I mean, if the player goes from /home to /players page I can use it like this:

components/players.svelte

import { getPlayerService } from &quot;main&quot;;

const playerService = await getPlayerService();
const players = await playerService.queryPlayers();

In this way, if the PlayerService does not exist, it is imported at the moment and returned, otherwise it returns the one imported and instantiated before.
Since the user switches pages frequently this way I can avoid the sudden creation and destruction of those clients, right?
But in this way I am using global variables which I don't like to use and I'm using verbose, DRY and long code in each component.
Is there a way to use the below code in components instead?
import { playerService } from &quot;main&quot;;

const players = await playerService.queryPlayers();

What do you suggest me to do?
Angular
If you use Angular you are able to use store. For example ngxs or ngrx modules for your application.
One more way in angular use resolvers.

Interface that classes can implement to be a data provider. A data
provider class can be used with the router to resolve data during
navigation. The interface defines a resolve() method that is invoked
when the navigation starts. The router waits for the data to be
resolved before the route is finally activated.

//player.resolver.ts
class PlayerResolver implements Resolve&lt;number&gt; {
   private req = false;
   private repSubject = new ReplaySubject(null);

   constructor(private service: PlayerServiceClient) { }

   public resolve(route: ActivatedRouteSnapshot): Observable {
        if (!this.req) {
            this.req = true;

            this.service.get().subscribe(res =&gt; this.repSubject.next(res));
        }
        return this.subject.pipe(first());
    }
}

//app-routing.module.ts
const routes: Routes = [
...
    {
     path: 'player'
     resolve: {data: PlayerResolver}
    },
    {
     path: 'friend'
     resolve: {data: FriendResolver}
    }
]

ReactiveX
If you use RxJs in your app, you would to do caching, create BaseSender:
//base.sender.ts
let hash = require('object-hash');

class BaseSender {

  ...
  protected httpSenderWithCache(service: Observable&lt;any&gt;,param): Observable&lt;any&gt; {
    const id = hash(param);

    if (!this.cache$[id]) {
      this.expireCache(id, time);
      this.cache$[id] = service.pipe(
        shareReplay(1), // last value
        catchError((err) =&gt; console.log(err))
      );
    }

    return this.cache$[id];
  }

}

shareReplay(1) gets last result.  const id = hash(param); generate unique hash for caching.
//player.service.ts
export class PlayerService extends BaseSender {
   ....
   public get(param = null): Observable&lt;any&gt; {
    param = param || {};

    const data = {
        url: 'https://example.com/player',
        options: {
          params: param,
        },
      };
    const request$ = this.http.get(data.url, data.options);

    return this.httpSenderWithCache(request$, data);
  }
}

General
If you don't use it all.

Install and configire inversify-binding-decorators with decorators for DI in app. In main.ts create container.

//main.ts
    import { injectable, Container } from &quot;inversify&quot;;
    import { provide, buildProviderModule } from &quot;inversify-binding-decorators&quot;; 
    import &quot;reflect-metadata&quot;;

    var container = new Container();
    // Reflects all decorators provided by this package and packages them into 
    // a module to be loaded by the container
    container.load(buildProviderModule());


Create interface ClientServiceInterface

//client-service.interface.ts
interface ClientServiceInterface {
  public get(param = null);
}


Create services

    @provide(PlayerServiceClient)
    export class PlayerServiceClient implements ClientServiceInterface {
    
      private result;
    
      public function get() {
         if(!result) {
           return fetch('https://ex.com/player')
                   .then(res =&gt; {
                      this.result = res;
                      return Promise.resolve(res) 
                    })
         }
         return Promise.resolve(result);  
      }
    }


in your components you have to inject service


  class PlayerComponent {
       constructor(private playerService: PlayerServiceClient) {
         playerService.get().then(...)
       }
    }