Angular懒加载Google Maps API重复加载报错求助
解决Angular Google Maps API重复加载问题
一、核心问题分析
即便使用根注入的单例服务,若加载逻辑未检查API是否已加载/正在加载,可能因异步操作的竞态条件(比如多个组件同时触发加载请求)导致重复发起API请求;另外,@angular/google-maps本身内置了API加载机制,若自定义加载逻辑和它冲突,也会触发重复加载报错。
二、正确实现方式
1. 完善单例MapService的加载逻辑
在服务中维护加载状态,确保只发起一次API请求,同时处理已加载、正在加载的场景:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, of } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class MapService { private apiLoaded = false; private loadingPromise: Promise<void> | null = null; private readonly apiKey = '你的Google Maps API密钥'; private readonly apiUrl = `https://maps.googleapis.com/maps/api/js?key=${this.apiKey}&callback=initMap`; constructor(private http: HttpClient) {} loadGoogleMapsApi(): Observable<boolean> { // 已加载直接返回成功状态 if (this.apiLoaded) { return of(true); } // 正在加载中,复用同一个Promise避免重复请求 if (this.loadingPromise) { return new Observable(observer => { this.loadingPromise?.then(() => { observer.next(true); observer.complete(); }); }); } // 首次发起加载请求 this.loadingPromise = new Promise((resolve, reject) => { // 全局声明JSONP所需的回调函数 (window as any).initMap = () => { this.apiLoaded = true; resolve(); }; this.http.jsonp(this.apiUrl, 'callback').subscribe({ next: () => {}, error: (err) => { this.loadingPromise = null; reject(err); } }); }); return new Observable(observer => { this.loadingPromise?.then(() => { observer.next(true); observer.complete(); }).catch(err => { observer.error(err); }); }); } }
2. 共享地图组件中调用服务
在组件的ngOnInit(而非构造函数)中调用服务的加载方法,确保组件初始化时触发加载,且仅等待一次加载完成:
import { Component, OnInit } from '@angular/core'; import { MapService } from './map.service'; @Component({ selector: 'app-shared-map', templateUrl: './shared-map.component.html', styleUrls: ['./shared-map.component.css'] }) export class SharedMapComponent implements OnInit { mapLoaded = false; constructor(private mapService: MapService) {} ngOnInit(): void { this.mapService.loadGoogleMapsApi().subscribe({ next: () => { this.mapLoaded = true; // 此处编写地图初始化逻辑 }, error: (err) => { console.error('Google Maps API加载失败:', err); } }); } }
3. 利用@angular/google-maps内置配置(更简洁方案)
@angular/google-maps的GoogleMapsModule提供了forRoot配置项,框架会自动处理单例加载,无需手动编写JSONP请求:
// app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { GoogleMapsModule } from '@angular/google-maps'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, GoogleMapsModule.forRoot({ apiKey: '你的Google Maps API密钥', // 可选:添加其他API参数,如语言、扩展库等 libraries: ['places'] }) ], providers: [], bootstrap: [AppComponent] }) export class AppModule {}
这种方式下,直接在共享组件中使用<google-map>组件即可,无需手动处理加载逻辑:
<!-- shared-map.component.html --> <google-map *ngIf="true" [center]="{lat: 40.7128, lng: -74.0060}" [zoom]="12"></google-map>
三、额外注意事项
- 确保项目中没有在
index.html等位置手动引入Google Maps API脚本,否则会和代码中的加载逻辑冲突。 - 仅在根模块使用
GoogleMapsModule.forRoot(),其他模块只需导入GoogleMapsModule(不带forRoot)。
内容的提问来源于stack exchange,提问作者Juano7894
相关产品推荐
相关产品推荐

