我正在开发一个带有 angular 8 和 ngrx 的应用程序。一切都很顺利,直到我在隐身模式下测试我的应用程序。突然,一个网址开始非常缓慢地工作,在导航开始和导航结束之间将近50秒。我观察到启用 redux-devtool 扩展似乎可以解决问题(每次都有效(。不知道这里发生了什么.需要时间的路由的解析器需要进行 3 次 api 调用,但这些调用在我单击路由的那一刻发生,但解析器需要 50 秒才能到达组件。以下是详细信息。如果还需要什么,请告诉我:
包.json
{
"name": "sfe",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve --configuration=proxy --proxy-config proxy.config.json",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "~8.2.14",
"@angular/common": "~8.2.14",
"@angular/compiler": "~8.2.14",
"@angular/core": "~8.2.14",
"@angular/forms": "~8.2.14",
"@angular/platform-browser": "~8.2.14",
"@angular/platform-browser-dynamic": "~8.2.14",
"@angular/router": "~8.2.14",
"@auth0/angular-jwt": "^4.0.0",
"@ngrx/effects": "^8.6.0",
"@ngrx/entity": "^8.6.0",
"@ngrx/router-store": "^8.6.0",
"@ngrx/schematics": "^8.6.0",
"@ngrx/store": "^8.6.0",
"@ngrx/store-devtools": "^8.6.0",
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "^4.0.0",
"core-js": "^2.5.4",
"include-media": "^1.4.9",
"moment": "^2.24.0",
"moment-timezone": "^0.5.28",
"node-sass": "~4.13.0",
"rxjs": "~6.4.0",
"rxjs-compat": "~6.4.0",
"tslib": "~1.9.0",
"webcomponents.js": "^0.7.24",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.803.25",
"@angular-devkit/build-webpack": "^0.803.2",
"@angular/cli": "~8.3.25",
"@angular/compiler-cli": "~8.2.14",
"@angular/language-service": "~8.2.14",
"@types/node": "~8.9.4",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.5.3"
}
}
app.module
import { AppEffects } from './app.effects';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, ErrorHandler } from '@angular/core';
import { TranslateModule, TranslateService, TranslateLoader } from '@ngx-translate/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { StoreModule } from '@ngrx/store';
import { reducers, metaReducers } from './reducers';
import { CoreModule } from './core/core.module';
import { AuthModule } from './features/auth/auth.module';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';
import { EffectsModule, Actions } from '@ngrx/effects';
import {RouterState, StoreRouterConnectingModule } from '@ngrx/router-store';
import { HttpClient } from '@angular/common/http';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { GlobalErrorHandler } from './core/error-handling/global-exception-handling';
import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
import { WindowRefService } from './core/services/window-ref.service';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AuthModule.forRoot(),
TranslateModule.forRoot(),
CoreModule.forRoot(),
AppRoutingModule,
StoreRouterConnectingModule.forRoot({
stateKey: 'router',
routerState:RouterState.Minimal
}),
StoreModule.forRoot(reducers, {
metaReducers,
runtimeChecks: {
strictStateImmutability: true,
strictActionImmutability: true
}
}),
StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production }),
EffectsModule.forRoot([AppEffects]),
StoreRouterConnectingModule.forRoot(),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
],
providers: [
WindowRefService,
{provide : LocationStrategy , useClass: HashLocationStrategy},
{
provide: TranslateService,
useClass: I18nService
},
{
provide: I18nService,
useExisting: TranslateService
},
{
provide: JWT_OPTIONS, useValue: JWT_OPTIONS
},
JwtHelperService,
{ provide: "BASE_API_URL", useValue: environment.apiUrl },
{ provide: ErrorHandler, useClass: GlobalErrorHandler }
],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }
路由模块.ts(延迟加载(
import { NotificationsResolver } from './resolvers/notifications.resolver';
import { NgModule } from '@angular/core';
import { Routes, RouterModule, CanActivate } from '@angular/router';
import { AuthGuard } from '../../auth/auth.guards';
const settingsroutes: Routes = [
{
path: '',
component: SettingsComponent,
children: [
{ path: 'notifications', component: SettingsComponent, data: { 'index': 1 }, resolve:{NotificationsResolver}},
],
canActivate: [AuthGuard]
}
];
@NgModule({
imports: [RouterModule.forChild(settingsroutes)],
exports: [RouterModule]
})
export class SettingsRoutingModule { }
解析器.ts
import { loadContactInfo, loadNotificationMobileCarriers } from './../ngrx/settings.actions';
import { areNotificationSettingsLoaded, areContactInfoLoaded, areNotificationMobileCarriersLoaded } from './../ngrx/settings.selectors';
import { getUserDetails } from '../../../auth/ngrx/auth.selectors';
import { User } from 'src/app/core/models/User';
import { tap, filter, finalize, first } from 'rxjs/operators';
import { Observable, concat, merge } from 'rxjs';
import { Store, select } from '@ngrx/store';
import { AppState } from '../../../../reducers/index';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
import { NotificationsRequestModel } from '../models/requestmodel/notifications-request.model';
import { loadNotificationSettings } from '../ngrx/settings.actions';
@Injectable()
export class NotificationsResolver implements Resolve<any>{
loadingNotifications = false;
loadingContactInfo = false;
loadingMobileCarriers = false;
notificationsRequest :NotificationsRequestModel = new NotificationsRequestModel();
userDetail$ : Observable<any>;
userDetail :User;
constructor(private store: Store<AppState>){
this.notificationsRequest.userId = 4000;
}
resolve(route:ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<any>{
const notificationSettingsData$=
this.store.pipe(
select(areNotificationSettingsLoaded),
tap(notificationSettingsLoaded => {
if(!this.loadingNotifications && !notificationSettingsLoaded){
this.loadingNotifications = true;
this.store.dispatch(loadNotificationSettings({requestParameter :this.notificationsRequest}));
}
}),
filter(NotificationSettingsLoaded => NotificationSettingsLoaded),
first(),
finalize(()=> {
this.loadingNotifications = false;
})
);
const contactInfoData$ =this.store.pipe(
select(areContactInfoLoaded),
tap(areContactInfoLoaded => {
if(!this.loadingContactInfo && !areContactInfoLoaded){
this.loadingContactInfo = true;
this.store.dispatch(loadContactInfo({requestParameter :this.notificationsRequest}));
}
}),
filter(ContactInfoLoaded => ContactInfoLoaded),
first(),
finalize(()=> {
this.loadingContactInfo = false;
})
);
const noificationMobileCarriers$ =this.store.pipe(
select(areNotificationMobileCarriersLoaded),
tap(areNotificationMobileCarriersLoaded => {
if(!this.loadingMobileCarriers && !areNotificationMobileCarriersLoaded){
this.loadingMobileCarriers = true;
this.store.dispatch(loadNotificationMobileCarriers());
}
}),
filter(NotificationMobileCarriersLoaded=> NotificationMobileCarriersLoaded),
first(),
finalize(()=> {
this.loadingMobileCarriers = false;
console.log("third one")
})
);
//This is done to enable two calls being made simultaneoulsy
return merge(contactInfoData$, notificationSettingsData$, noificationMobileCarriers$)
}
}
appComponent.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
t1 : any;
t0 : any;
constructor(translate: TranslateService, private router: Router, private activatedRoute: ActivatedRoute,
private store: Store<AppState>) {
}
ngOnInit(): void {
this.router.events.subscribe(event => {
switch (true) {
case event instanceof NavigationStart: {
this.t0 = performance.now();
this.loading = true;
break;
}
case event instanceof NavigationEnd:
case event instanceof NavigationCancel:
case event instanceof NavigationError: {
this.t1 = performance.now();
this.loading = false;
console.log(this.t1-this.t0);
break;
}
default: {
break;
}
}
});
//load sub params
}
}
我看到的问题是 reducer 中的名称冲突,并且您可以使用forkJoin
并行执行所有请求而不是merge
。
this.store.dispatch(loadNotificationMobileCarriers())
- 它也需要requestParameter
吗?
请尝试在下面编码,如果它不起作用 - 请检查控制台日志是否打印所有 3done
并在下面的评论中告诉我。
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
const notificationSettingsData$ =
this.store.pipe(
select(areNotificationSettingsLoaded),
tap(flag => {
if (!this.loadingNotifications && !flag) {
this.loadingNotifications = true;
this.store.dispatch(loadNotificationSettings({requestParameter: this.notificationsRequest}));
}
}),
filter(flag => flag),
first(),
finalize(() => {
this.loadingNotifications = false;
}),
);
const contactInfoData$ = this.store.pipe(
select(areContactInfoLoaded),
tap(flag => {
if (!this.loadingContactInfo && !flag) {
this.loadingContactInfo = true;
this.store.dispatch(loadContactInfo({requestParameter: this.notificationsRequest}));
}
}),
filter(flag => flag),
first(),
finalize(() => {
this.loadingContactInfo = false;
}),
);
const noificationMobileCarriers$ = this.store.pipe(
select(areNotificationMobileCarriersLoaded),
tap(flag => {
if (!this.loadingMobileCarriers && !flag) {
this.loadingMobileCarriers = true;
this.store.dispatch(loadNotificationMobileCarriers());
}
}),
filter(flag => flag),
first(),
finalize(() => {
this.loadingMobileCarriers = false;
}),
);
return forkJoin({
contactInfoData: contactInfoData$.pipe(tap(() => console.log('contactInfoData$ done'))),
notificationSettingsData: notificationSettingsData$.pipe(tap(() => console.log('notificationSettingsData$ done'))),
noificationMobileCarriers: noificationMobileCarriers$.pipe(tap(() => console.log('noificationMobileCarriers$ done'))),
});
}