## **What is Lazy Loading?**

Lazy loading is a **code optimization technique** that is also called **code splitting**. It is used to load the code only when it is needed in order to **reduce the initial bundle size** but also the **load time** of the application. In order to lazy load code we use the **dynamic import syntax**.

For example, we can lazy load a module like this:

```
import("./my-component").then((file) =&gt; {
  // do something with the component
});
```

By doing this, we are telling the bundler to create a separate bundle for the module and load it only when the code is executed.

Intermediate workshop

### Modern Angular

Master the latest Angular features to build modern applications. Learn how to use standalone components, signals, the new inject method and much more.

[Learn more](/workshop/modern-angular)

## **How to Lazy Load a Service in Angular?**

Yes, we will use the dynamic import syntax. But, not only that! Because the services in Angular use the **Injectable** **decorator**, it means they are injectable and may also depend on other services. So, we cannot just lazy load the service and use it directly as a normal class.

What we have to do is to use the dynamic import syntax to lazy load the service and then use the **injector** to get the **service instance**. For example, we can lazy load a service like this:

```
import("./my-service").then((file) =&gt; {
  const service = this.injector.get(file.MyService);
  // do something with the service
});
```

This is great, but doesn’t give us a **good DX (developer experience)**.

So, we can create a **helper function** that will lazy load the service and return the service instance. Here’s a helper function that can help us with that.

```
export function lazyLoadService<t>(loader: () =&gt; Promise<t>): Promise<t> {
  const injector = inject(Injector);

  return loader().then((serviceClass) =&gt; {
    const service = injector.get(serviceClass);
    return service;
  });
}</t></t></t>
```

Let’s return an **Observable** instead of a **Promise,** as it’s more **convenient** to use in Angular, and **easier to chain**.

```
export function lazyService<t>(loader: () =&gt; Promise<type<t>&gt;): Observable<t> {
  const injector = inject(Injector);

  return defer(() =&gt; {
    return loader().then((service) =&gt; injector.get(service));
  });
}</t></type<t></t>
```

The **defer** operator will create an Observable that will execute the loader function only when the Observable is **subscribed** **to**. So, we can use it like this:

```
lazyService(() =&gt; import("./my-service")).subscribe((service) =&gt; {
  // do something with the service
});
```

or better yet, we can pipe the service observable:

```
lazyService(() =&gt; import("./my-service")).pipe(
  concatMap((service) =&gt; {
    // do something with the service
  })
);
```

Let’s see an example of how to use it in a component:

```
const DataServiceImport = () =&gt; 
  import('./data.service').then((m) =&gt; m.DataService);

@Component({
  template: `
    <ul>
      <li *ngfor="let todo of todos$ | async">
        {{ todo.title }}
      </li>
    </ul>
  `,
  standalone: true,
  imports: [NgFor, AsyncPipe],
})
export class AppComponent {
  private dataService$ = lazyService(DataServiceImport);

  todos$ = this.dataService$.pipe(concatMap((s) =&gt; s.getTodos()));
}
```

And now, let’s take a look at the network tab!

Yeah, the service will be in it’s own bundle 🎉!

But what if we want to use the service in another component, **we have to lazy load it again**. Otherwise, it will be bundled in **main bundle** (_if used in not lazy loaded component_), or **common bundle** (_if used in another lazy loaded component_), and break the code splitting.

> NOTE: The javascript bundle will be downloaded only once, no matter of how many times we lazy load it, because after the first download, webpack (the bundler) will just reuse the downloaded bundled.

## **Different ways to lazy load a service**

Take a look at these tweets by [Younes](https://medium.com/u/31a8ee710c55?source=post_page-----cfbaf586d54e--------------------------------), where he explains different ways to lazy load a service in Angular:

**What’s the use case for lazy loading a service?**

Let’s say we have 2 Services (**ServiceOne** and **ServiceTwo**) and 3 Components: **ComponentA**, **ComponentB**, and **ComponentC**.

*   ComponentA — uses → ServiceOne
    
*   ComponentB — uses → ServiceOne and ServiceTwo
    
*   ComponentC — uses → ServiceOne and ServiceTwo
    

Since **ServiceOne** and **ServiceTwo** are being imported **\_\_statically\_\_** in all components, Angular (Webpack) puts both Services in a **common** bundle.

But this **common** bundle isn’t loaded until we lazy-load one of the components. Now, when we lazy-load **ComponentA**, common bundle gets loaded but it includes both Services even when **ComponentA** only uses **ServiceOne**. (Credits: [Chau Tran](https://twitter.com/Nartc1410))

Another use case is when we have very dynamic applications, meaning that we load components dynamically and maybe based on configs, and these components may use different services or the same services. But because we don’t know which services will be used, we can’t bundle them in the main bundle otherwise it will get big! So, we can lazy load the services and load them only when they are needed.

## **Conclusion**

> I want to give a shoutout to [@yjaaidi](https://twitter.com/yjaaidi) for his great research on lazy loading services in Angular. He is the one who inspired me to write this article. So, go ahead and follow him on [Twitter](https://twitter.com/yjaaidi).

After Ivy’s rollout, everything in Angular has become easier to work with. Lazy loading services is no exception!
