面试题答案
一键面试缓存机制
- 服务端缓存:
- 在服务端配置合适的缓存策略,例如使用HTTP缓存头(如
Cache - Control
、ETag
等)。对于不经常变化的数据,设置较长的缓存时间。当客户端发起请求时,服务端可以根据缓存头判断是否直接返回缓存的数据,减少处理时间和网络传输。 - 示例:在Node.js的Express应用中,可以使用
express - static - gzip
中间件来设置缓存头。
const express = require('express'); const app = express(); const staticGzip = require('express - static - gzip'); app.use(staticGzip('public', { enableBrotli: true, orderPreference: ['br', 'gzip'], setHeaders: function (res, path) { res.set('Cache - Control','max - age = 31536000, public'); } }));
- 在服务端配置合适的缓存策略,例如使用HTTP缓存头(如
- 客户端缓存:
- 在Angular应用中,可以创建一个自定义的缓存服务。利用
Map
对象来存储缓存数据,键为请求的URL,值为请求结果。每次发起请求前,先检查缓存中是否有对应的数据。
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class CacheService { private cache = new Map<string, any>(); getCache(key: string) { return this.cache.get(key); } setCache(key: string, value: any) { this.cache.set(key, value); } }
- 在数据请求服务中使用该缓存服务:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { CacheService } from './cache.service'; @Injectable({ providedIn: 'root' }) export class DataService { constructor(private http: HttpClient, private cacheService: CacheService) {} getData(url: string) { const cachedData = this.cacheService.getCache(url); if (cachedData) { return Promise.resolve(cachedData); } return this.http.get(url).toPromise().then(data => { this.cacheService.setCache(url, data); return data; }); } }
- 在Angular应用中,可以创建一个自定义的缓存服务。利用
重试机制
- 简单重试:
- 可以利用
rxjs
的retry
操作符。在Angular的HttpClient
请求返回的Observable
上使用retry
,设置重试次数。
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { catchError, retry } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class DataService { constructor(private http: HttpClient) {} getData(url: string) { return this.http.get(url).pipe( retry(3), catchError(error => { console.error('Error after retries:', error); throw error; }) ); } }
- 可以利用
- 指数退避重试:
- 随着重试次数增加,延迟时间呈指数增长。可以使用
rxjs
的retryWhen
和delay
操作符实现。
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { catchError, retryWhen, delay, scan } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class DataService { constructor(private http: HttpClient) {} getData(url: string) { return this.http.get(url).pipe( retryWhen(errors => errors.pipe( scan((acc, error) => { if (acc >= 3) { throw error; } return acc + 1; }, 0), delay(errorCount => Math.pow(2, errorCount) * 1000) ) ), catchError(error => { console.error('Error after retries:', error); throw error; }) ); } }
- 随着重试次数增加,延迟时间呈指数增长。可以使用
数据压缩
- 服务端压缩:
- 在服务端启用数据压缩。例如在Node.js应用中,可以使用
compression
中间件。它支持gzip
和deflate
压缩算法。
const express = require('express'); const app = express(); const compression = require('compression'); app.use(compression());
- 在服务端启用数据压缩。例如在Node.js应用中,可以使用
- 客户端支持:
- Angular的
HttpClient
默认支持接收压缩后的数据。当服务端返回压缩数据时,HttpClient
会自动解压缩。无需额外配置,但要确保在请求头中设置Accept - Encoding: gzip, deflate
(HttpClient
默认会设置)。
- Angular的
优化请求频率
- 合并请求:
- 如果有多个相关的请求,可以将它们合并为一个请求。例如,假设需要获取用户信息和用户的订单列表,可以在服务端提供一个接口,一次性返回这两个数据。
- 在Angular中,可以使用
forkJoin
来合并多个Observable
请求。
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { forkJoin } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class DataService { constructor(private http: HttpClient) {} getCombinedData() { const userInfo$ = this.http.get('/api/user'); const orderList$ = this.http.get('/api/orders'); return forkJoin([userInfo$, orderList$]); } }
- 防抖与节流:
- 防抖:如果用户频繁触发某个操作导致多次请求(例如搜索框输入),可以使用防抖。在Angular中,可以结合
rxjs
的debounceTime
操作符。
import { Component } from '@angular/core'; import { fromEvent } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; @Component({ selector: 'app - search', templateUrl: './search.component.html' }) export class SearchComponent { constructor() { const searchInput = document.getElementById('search - input'); if (searchInput) { fromEvent(searchInput, 'input').pipe( debounceTime(300) ).subscribe(() => { // 执行搜索请求 }); } } }
- 节流:控制请求在一定时间间隔内只能触发一次。可以使用
rxjs
的throttleTime
操作符。
import { Component } from '@angular/core'; import { fromEvent } from 'rxjs'; import { throttleTime } from 'rxjs/operators'; @Component({ selector: 'app - throttle', templateUrl: './throttle.component.html' }) export class ThrottleComponent { constructor() { const clickButton = document.getElementById('click - button'); if (clickButton) { fromEvent(clickButton, 'click').pipe( throttleTime(1000) ).subscribe(() => { // 执行请求 }); } } }
- 防抖:如果用户频繁触发某个操作导致多次请求(例如搜索框输入),可以使用防抖。在Angular中,可以结合
网络状态监测与处理
- 监测网络状态:
- 使用
@angular/common/http
中的HttpClient
结合rxjs
的map
操作符来监测网络请求的状态。可以创建一个服务来统一处理。
import { Injectable } from '@angular/core'; import { HttpClient, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class NetworkService { isOnline = true; constructor(private http: HttpClient) {} checkNetwork() { return this.http.get('/api/healthcheck').pipe( map(() => { this.isOnline = true; return true; }, () => { this.isOnline = false; return false; }) ); } }
- 使用
- 网络变化处理:
- 可以结合浏览器的
online
和offline
事件,在网络状态变化时进行相应处理。例如,当网络离线时,显示提示信息,停止不必要的请求;当网络恢复时,重新尝试未完成的请求。
import { Component, OnInit } from '@angular/core'; import { NetworkService } from './network.service'; @Component({ selector: 'app - network - monitor', templateUrl: './network - monitor.component.html' }) export class NetworkMonitorComponent implements OnInit { constructor(private networkService: NetworkService) {} ngOnInit() { window.addEventListener('offline', () => { this.networkService.isOnline = false; // 显示离线提示 }); window.addEventListener('online', () => { this.networkService.isOnline = true; // 重新尝试未完成的请求 }); } }
- 可以结合浏览器的