Angular caching to supercharge your app


Difficulty

Performance plays a crucial role in today’s web applications, and Angular offers powerful tools like caching to enhance user experience and reduce server load. This article delves into implementing efficient caching strategies using both cache services and HTTP interceptors in Angular, providing you with comprehensive code examples and best practices.

Understanding the landscape: types of caching in Angular

Angular offers two primary approaches to caching:

  1. Cache Service: A custom service dedicated to storing and retrieving data, often leveraging technologies like IndexedDB or Web Storage.
  2. HTTP Interceptor: A service that intercepts outgoing and incoming HTTP requests, enabling manipulation of the request/response flow for caching purposes.

Choosing the right approach depends on your specific needs and the type of data you want to cache.

Building a custom cache service: storing and retrieving data

Let’s create a simple CacheService using the browser’s localStorage:

import { Injectable } from '@angular/core';

interface CacheEntry<T> {
  data: T;
  timestamp: number;
}

@Injectable({
  providedIn: 'root'
})
export class CacheService {
  private cache: { [key: string]: CacheEntry<any> } = {};

  set(key: string, data: any, ttl?: number) {
    this.cache[key] = { data, timestamp: Date.now() + (ttl || 60 * 60 * 1000) }; // Default to 1 hour TTL
  }

  get(key: string): any | null {
    const entry = this.cache[key];
    if (entry && entry.timestamp > Date.now()) {
      return entry.data;
    }
    return null;
  }

  remove(key: string) {
    delete this.cache[key];
  }
}

This service provides basic methods for storing data with optional time-to-live (TTL) and expiration handling. You can customize it further to include features like eviction strategies or support for more complex data structures.

Intercepting HTTP requests: Angular caching at the Network Level

Now, let’s see how to leverage HTTP interceptors for caching:

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpRequest,
  HttpResponse,
  HttpHandler,
  HttpCacheStore,
} from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class CacheInterceptor implements HttpInterceptor {
  constructor(private cacheStore: HttpCacheStore) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const cachedResponse = this.cacheStore.get(req);
    if (cachedResponse) {
      return of(cachedResponse);
    }

    return next.handle(req).pipe(
      tap(event => {
        if (event instanceof HttpResponse) {
          this.cacheStore.put(req, event);
        }
      })
    );
  }
}

This interceptor checks the HttpCacheStore for existing responses before making a network request. If found, it directly returns the cached response, improving performance. Additionally, it stores successful responses in the cache for future use.

Remember to register the interceptor in your AppModule for it to take effect.

Putting it together: implementing a caching strategy

Here’s a basic example of utilizing both approaches:

// Service using cache service
constructor(private cacheService: CacheService) {}

getData(key: string) {
  const cachedData = this.cacheService.get(key);
  if (cachedData) {
    return of(cachedData);
  }

  // Make API call and store response in cache
  return this.http.get<any>(`https://api.example.com/data/${key}`).pipe(
    tap(data => this.cacheService.set(key, data))
  );
}

// Service using HTTP interceptor
constructor(private http: HttpClient) {}

getData(key: string) {
  return this.http.get<any>(`https://api.example.com/data/${key}`);
}

In this example, the first service checks the local cache for data before making an API call, while the second leverages the interceptor for automatic caching of API responses.

Conclusion

Choose the right approach between performance and complexity trade-offs. That’s all about caching in an Angular app.

Try it at home!

0
Be the first one to like this.
Please wait...

Leave a Reply

Thanks for choosing to leave a comment.
Please keep in mind that all comments are moderated according to our comment policy, and your email address will NOT be published.
Please do NOT use keywords in the name field. Let's have a personal and meaningful conversation.