当前位置: 首页 > news >正文

全面分析一下前端框架Angular的来龙去脉,分析angular的技术要点和难点,以及详细的语法和使用规则,底层原理-小白进阶之路

Angular 前端框架全面分析

Angular 是一个由 Google 维护的开源前端框架。它最早在 2010 年发布,最初版本称为 AngularJS。2016 年,团队发布了一个完全重写的版本,称为 Angular 2,之后的版本(如 Angular 4、Angular 5 等)都统称为 Angular。

一、历史背景

1. AngularJS(Angular 1.x)

  • 发布年份:2010
  • 特点:基于 MVC(Model-View-Controller)架构,使用双向数据绑定和依赖注入。
  • 限制:性能瓶颈、可维护性差、学习曲线陡峭。

2. Angular 2+

  • 发布年份:2016
  • 特点:完全重写,采用基于组件的架构,使用 TypeScript 开发,提升了性能和可维护性。
  • 发展:从 Angular 2 开始,Angular 团队每半年发布一个大版本,当前最新版本为 Angular 15。

二、技术要点

1. TypeScript

Angular 使用 TypeScript 编写,提供了静态类型检查、现代 JavaScript 特性等优点,有助于提高代码质量和开发效率。

2. 组件化

采用组件式开发,将应用程序分割成独立的、可复用的组件,每个组件包含自己的模板、样式和逻辑。

3. 模块化

使用 NgModule 来组织代码,一个 NgModule 可以包含组件、指令、管道和服务等,提供了良好的模块化支持。

4. 依赖注入

Angular 提供了强大的依赖注入机制,简化了服务的创建和管理,提高了代码的可测试性和可维护性。

5. 模板语法

Angular 使用直观的模板语法来定义组件的视图,支持数据绑定、指令和事件绑定等。

6. 路由

Angular 内置强大的路由模块,可以轻松地定义应用程序的导航和页面切换。

7. 表单处理

提供了两种表单处理方式:模板驱动表单和响应式表单,满足不同需求。

8. RxJS

Angular 大量使用 RxJS(Reactive Extensions for JavaScript)来处理异步数据流,非常适合复杂的数据交互场景。

三、技术难点

1. 学习曲线

由于 Angular 涉及的概念较多(如依赖注入、RxJS、TypeScript 等),学习曲线相对较陡。

2. 性能优化

理解和应用 Angular 的变更检测机制和 Zone.js 是性能优化的关键,需要一定的深入学习。

3. 复杂项目管理

随着项目规模的扩大,如何有效地管理模块、组件、服务等也是一个挑战。

四、详细语法和使用规则

1. 组件

import { Component } from '@angular/core';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
})
export class AppComponent {title = 'my-angular-app';
}

2. 模块

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';import { AppComponent } from './app.component';@NgModule({declarations: [AppComponent],imports: [BrowserModule],providers: [],bootstrap: [AppComponent]
})
export class AppModule { }

3. 数据绑定

  • 插值绑定{{ expression }}
  • 属性绑定[property]="expression"
  • 事件绑定(event)="handler"
  • 双向绑定[(ngModel)]="property"

4. 指令

  • 结构型指令*ngIf, *ngFor
  • 属性型指令[ngClass], [ngStyle]

5. 服务和依赖注入

import { Injectable } from '@angular/core';@Injectable({providedIn: 'root',
})
export class DataService {getData() {return ['data1', 'data2', 'data3'];}
}

6. 路由

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent }```typescript
import { AboutComponent } from './about/about.component';const routes: Routes = [{ path: '', component: HomeComponent },{ path: 'about', component: AboutComponent }
];@NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule]
})
export class AppRoutingModule { }

7. 模板驱动表单

<form #form="ngForm" (ngSubmit)="onSubmit(form)"><input type="text" name="username" ngModel required><button type="submit">Submit</button>
</form>

8. 响应式表单

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';@Component({selector: 'app-form',templateUrl: './form.component.html'
})
export class FormComponent implements OnInit {form: FormGroup;constructor(private fb: FormBuilder) { }ngOnInit() {this.form = this.fb.group({username: ['', Validators.required]});}onSubmit() {console.log(this.form.value);}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()"><input formControlName="username"><button type="submit">Submit</button>
</form>

五、底层原理

1. 变更检测机制

Angular 使用 Zone.js 来捕获异步操作,然后触发变更检测机制来更新视图。变更检测机制的核心是脏值检测策略,Angular 会对比数据的当前值和之前的值,决定是否重新渲染视图。

2. 依赖注入机制

Angular 的依赖注入机制基于提供者(Provider)和注入器(Injector)。每个服务、组件等都可以声明依赖项,Angular 会根据依赖关系图自动注入所需的依赖。

3. 编译过程

Angular 的编译过程分为 AOT(Ahead-of-Time)和 JIT(Just-in-Time)两种模式:

  • AOT 编译:在构建时进行编译,生成优化后的 JavaScript 代码,减少应用运行时的开销,提高性能。
  • JIT 编译:在浏览器中运行时进行编译,适合开发阶段使用。

4. 渲染机制

Angular 使用虚拟 DOM 进行渲染优化,类似于 React。通过虚拟 DOM,Angular 可以高效地计算出需要更新的部分,减少直接操作真实 DOM 的次数,从而提高性能。

5. 模块化

Angular 的模块系统通过 NgModule 实现。每个 NgModule 都有自己的执行环境,可以包含组件、指令、管道和服务等。模块化设计有助于代码分离和按需加载,提高了应用的可维护性和性能。

六、模块化

Angular 是一个功能强大且全面的前端框架,适用于大规模、复杂的 Web 应用开发。它采用 TypeScript 进行开发,提供了丰富的工具和功能(如依赖注入、变更检测、模块化、路由等),尽管学习曲线较陡,但在大型项目中表现出色。掌握 Angular 的核心概念和原理,能够帮助开发者构建高性能、高可维护性的 Web 应用。
当然,下面是关于 Angular 的更多详细信息,包括一些高级特性、最佳实践以及常见的开发模式。

七、高级特性

1. 懒加载(Lazy Loading)

懒加载是 Angular 中提高性能的重要特性。通过懒加载,可以按需加载模块而不是在应用启动时加载所有模块。

const routes: Routes = [{ path: 'home', component: HomeComponent },{ path: 'about', loadChildren: () => import('./about/about.module').then(m => m.AboutModule) }
];

2. Angular CLI

Angular CLI 是一个强大的命令行工具,用于初始化、开发、构建和维护 Angular 应用程序。

# 安装 Angular CLI
npm install -g @angular/cli# 创建新项目
ng new my-angular-app# 启动开发服务器
ng serve# 生成组件、服务等
ng generate component my-component

3. 国际化(i18n)

Angular 提供了内置的国际化支持,可以轻松地将应用程序本地化到多种语言。

import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';registerLocaleData(localeFr, 'fr');

4. 动态组件加载

在运行时动态加载和渲染组件是 Angular 的一个高级特性,适用于需要根据用户交互动态生成内容的场景。

import { Component, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core';@Component({selector: 'app-dynamic-loader',template: `<ng-container #container></ng-container>`
})
export class DynamicLoaderComponent {@ViewChild('container', { read: ViewContainerRef, static: true }) container: ViewContainerRef;constructor(private resolver: ComponentFactoryResolver) { }loadComponent(component: any) {const factory = this.resolver.resolveComponentFactory(component);this.container.clear();this.container.createComponent(factory);}
}

5. 服务端渲染(SSR)

使用 Angular Universal 可以实现服务端渲染,从而提高应用的 SEO 和首屏加载速度。

# 安装 Angular Universal
ng add @nguniversal/express-engine# 构建和运行 SSR 应用
npm run build:ssr
npm run serve:ssr

八、最佳实践

1. 代码组织

  • 模块化设计:将应用分为多个功能模块,每个模块负责特定功能。
  • 组件化设计:尽量将界面划分为独立的组件,提升可复用性。
  • 服务层:将业务逻辑和数据访问层抽象为服务,组件只负责视图逻辑。

2. 性能优化

  • 使用懒加载:按需加载模块,减少首屏加载时间。
  • 避免不必要的变更检测:使用 OnPush 变更检测策略,减少不必要的视图更新。
  • 异步操作:尽量使用异步操作,如 async 管道、PromiseObservable

3. 代码规范

  • 使用 TypeScript:充分利用 TypeScript 的静态类型检查,提升代码质量。
  • 遵循 Angular 风格指南:遵循官方提供的风格指南,保持代码一致性和可维护性。
  • 单元测试和端到端测试:编写单元测试和端到端测试,确保代码的正确性和稳定性。

九、常见开发模式

1. 智能组件和哑组件

  • 智能组件:负责处理业务逻辑和与服务的交互。
  • 哑组件:只负责展示数据和处理简单的用户交互。
// 智能组件
@Component({selector: 'app-smart',template: `<app-dumb [data]="data" (event)="handleEvent($event)"></app-dumb>`
})
export class SmartComponent {data = this.dataService.getData();constructor(private dataService: DataService) { }handleEvent(event: any) { /* 处理事件 */ }
}// 哑组件
@Component({selector: 'app-dumb',template: `<div *ngFor="let item of data">{{ item }}</div>`
})
export class DumbComponent {@Input() data: any[];@Output() event = new EventEmitter<any>();
}

2. 状态管理

对于复杂的应用,可以采用状态管理库(如 NgRx)来管理应用状态当然,接下来我会详细介绍 Angular 的状态管理、单元测试、与其他技术的集成,以及一些高级调试技巧。

十、状态管理

1. NgRx

NgRx 是 Angular 中常用的状态管理库,基于 Redux 架构,提供了单一状态树、不可变状态、纯函数 reducer 等特点。

安装 NgRx
ng add @ngrx/store
ng add @ngrx/effects
状态定义

定义状态接口和初始状态:

// state.ts
export interface AppState {count: number;
}export const initialState: AppState = {count: 0,
};
Actions

定义 actions:

// actions.ts
import { createAction, props } from '@ngrx/store';export const increment = createAction('[Counter] Increment');
export const decrement = createAction('[Counter] Decrement');
export const reset = createAction('[Counter] Reset', props<{ count: number }>());
Reducer

定义 reducer:

// reducer.ts
import { createReducer, on } from '@ngrx/store';
import { increment, decrement, reset } from './actions';
import { AppState, initialState } from './state';const _counterReducer = createReducer(initialState,on(increment, state => ({ ...state, count: state.count + 1 })),on(decrement, state => ({ ...state, count: state.count - 1 })),on(reset, (state, { count }) => ({ ...state, count }))
);export function counterReducer(state: AppState | undefined, action: Action) {return _counterReducer(state, action);
}
Store Module

在应用模块中引入 Store 模块:

import { StoreModule } from '@ngrx/store';
import { counterReducer } from './reducer';@NgModule({imports: [StoreModule.forRoot({ count: counterReducer }),],
})
export class AppModule { }
使用 Store

在组件中使用 Store:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from './state';
import { increment, decrement, reset } from './actions';@Component({selector: 'app-counter',template: `<div>Count: {{ count$ | async }}</div><button (click)="increment()">Increment</button><button (click)="decrement()">Decrement</button><button (click)="reset(0)">Reset</button>`
})
export class CounterComponent {count$ = this.store.select(state => state.count);constructor(private store: Store<AppState>) {}increment() {this.store.dispatch(increment());}decrement() {this.store.dispatch(decrement());}reset(value: number) {this.store.dispatch(reset({ count: value }));}
}

2. Akita

Akita 是另一种用于 Angular 的状态管理库,提供了灵活的状态管理方式,适合大型应用。

安装 Akita
ng add @datorama/akita
定义 Store
import { Store, StoreConfig } from '@datorama/akita';export interface AppState {count: number;
}export function createInitialState(): AppState {return {count: 0,};
}@StoreConfig({ name: 'app' })
export class AppStore extends Store<AppState> {constructor() {super(createInitialState());}
}
使用 Store
import { Component } from '@angular/core';
import { AppStore } from './app.store';@Component({selector: 'app-counter',template: `<div>Count: {{ count$ | async }}</div><button (click)="increment()">Increment</button><button (click)="decrement()">Decrement</button><button (click)="reset()">Reset</button>`
})
export class CounterComponent {count$ = this.appStore.select(state => state.count);constructor(private appStore: AppStore) {}increment() {this.appStore.update(state => ({ count: state.count + 1 }));}decrement() {this.appStore.update(state => ({ count: state.count - 1 }));}reset() {this.appStore.reset();}
}

十一、单元测试

Angular 提供了强大的单元测试支持,使用 Karma 和 Jasmine 进行测试。

1. 设置测试环境

Angular CLI 自动生成的项目已经配置好了 Karma 和 Jasmine,无需额外配置。

2. 编写测试当然,我将继续深入探讨 Angular 的单元测试、与其他技术的集成、以及一些高级调试技巧。

十一、单元测试(继续)

2. 编写测试

组件测试

使用 TestBed 创建组件并进行测试:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CounterComponent } from './counter.component';describe('CounterComponent', () => {let component: CounterComponent;let fixture: ComponentFixture<CounterComponent>;beforeEach(async () => {await TestBed.configureTestingModule({declarations: [ CounterComponent ]}).compileComponents();});beforeEach(() => {fixture = TestBed.createComponent(CounterComponent);component = fixture.componentInstance;fixture.detectChanges();});it('should create', () => {expect(component).toBeTruthy();});it('should increment count', () => {component.increment();expect(component.count).toBe(1);});it('should decrement count', () => {component.decrement();expect(component.count).toBe(-1);});it('should reset count', () => {component.reset(0);expect(component.count).toBe(0);});
});
服务测试

测试服务时,使用 TestBed 配置提供者:

import { TestBed } from '@angular/core/testing';
import { DataService } from './data.service';describe('DataService', () => {let service: DataService;beforeEach(() => {TestBed.configureTestingModule({});service = TestBed.inject(DataService);});it('should be created', () => {expect(service).toBeTruthy();});it('should get data', () => {const data = service.getData();expect(data).toEqual(['item1', 'item2']);});
});

3. 运行测试

使用 Angular CLI 运行测试:

ng test

十二、与其他技术的集成

1. 与后端 API 的集成

使用 Angular 的 HttpClient 模块来与后端 API 进行通信。

安装 HttpClient 模块
import { HttpClientModule } from '@angular/common/http';@NgModule({imports: [ HttpClientModule ],
})
export class AppModule { }
创建服务
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';@Injectable({providedIn: 'root',
})
export class ApiService {constructor(private http: HttpClient) {}getData(): Observable<any> {return this.http.get('https://api.example.com/data');}postData(data: any): Observable<any> {return this.http.post('https://api.example.com/data', data);}
}
使用服务
import { Component, OnInit } from '@angular/core';
import { ApiService } from './api.service';@Component({selector: 'app-data',template: `<div *ngFor="let item of data">{{ item }}</div>`,
})
export class DataComponent implements OnInit {data: any;constructor(private apiService: ApiService) {}ngOnInit() {this.apiService.getData().subscribe(data => this.data = data);}
}

2. 与第三方库的集成

Angular 可以轻松集成第三方库,如 RxJS、Lodash 等。

使用 RxJS
import { of } from 'rxjs';
import { map } from 'rxjs/operators';const observable = of(1, 2, 3).pipe(map(x => x * 2)
);observable.subscribe(value => console.log(value)); // 输出 2, 4, 6
使用 Lodash
import * as _ from 'lodash';const array = [1, 2, 3, 4];
const doubled = _.map(array, x => x * 2);
console.log(doubled); // 输出 [2, 4, 6, 8]

当然,我将继续介绍更多关于 Angular 的内容,包括高级调试技巧、动画、表单处理、以及一些常见的开发工具和资源。

十三、高级调试技巧(继续)

2. 使用 Debug 模式

启用 Debug 模式

在开发过程中,可以启用 Angular 的 Debug 模式,以便在控制台中查看详细的调试信息。

import { enableProdMode } from '@angular/core';if (environment.production) {enableProdMode();
} else {// 开发模式下启用调试信息import('zone.js/plugins/zone-error');  // Included with Angular CLI.
}

3. Angular 调试工具

使用 ng.probe

在浏览器控制台中,可以使用 ng.probe 方法来访问组件实例和调试信息。

// 获取组件实例
const component = ng.probe(document.querySelector('app-root')).componentInstance;
console.log(component);
使用 Augury

Augury 是一个用于调试 Angular 应用的 Chrome 扩展,提供组件树、依赖注入、路由等信息的可视化展示。

安装 Augury
  • 在 Chrome 浏览器中,访问 Augury 页面并安装扩展。
使用 Augury
  • 打开 Chrome 开发者工具,切换到 Augury 标签,可以查看组件树、依赖关系等信息。

十四、动画

Angular 提供了强大的动画支持,通过 Angular Animations 模块可以实现复杂的动画效果。

1. 安装 Angular Animations

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';@NgModule({imports: [BrowserAnimationsModule],
})
export class AppModule {}

2. 定义动画

使用 triggerstatestyletransitionanimate 来定义动画。

import { trigger, state, style, transition, animate } from '@angular/animations';@Component({selector: 'app-animated',template: `<div [@fadeInOut]="'in'">Fade In Out Animation</div><button (click)="toggleState()">Toggle State</button>`,animations: [trigger('fadeInOut', [state('in', style({ opacity: 1 })),transition(':enter', [style({ opacity: 0 }),animate(600)]),transition(':leave', [animate(600, style({ opacity: 0 }))])])]
})
export class AnimatedComponent {state = 'in';toggleState() {this.state = this.state === 'in' ? 'out' : 'in';}
}

十五、表单处理

Angular 提供了两种表单处理方式:模板驱动表单和响应式表单。

1. 模板驱动表单

模板驱动表单使用 Angular 的指令和模板语法来处理表单。

import { FormsModule } from '@angular/forms';@NgModule({imports: [FormsModule],
})
export class AppModule {}
<!-- template-driven-form.component.html -->
<form #form="ngForm" (ngSubmit)="onSubmit(form)"><label for="name">Name:</label><input type="text" id="name" name="name" ngModel><button type="submit">Submit</button>
</form>
// template-driven-form.component.ts
import { Component } from '@angular/core';@Component({selector: 'app-template-driven-form',templateUrl: './template-driven-form.component.html'
})
export class TemplateDrivenFormComponent {onSubmit(form: any) {console.log('Form Data:', form.value);}
}

2. 响应式表单

响应式表单使用 FormBuilderFormGroup 来处理表单。

import { ReactiveFormsModule, FormBuilder, FormGroup } from '@angular/forms';@NgModule({imports: [ReactiveFormsModule],
})
export class AppModule {}
<!-- reactive-form.component.html -->
<form [formGroup]="form" (ngSubmit)="onSubmit()"><label for="name">Name:</label><input type="text" id="name" formControlName="name"><button type="submit">Submit</button>
</form>
// reactive-form.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';@Component({selector: 'app-reactive-form',templateUrl: './react### 2. **响应式表单**响应式表单使用 `FormBuilder``FormGroup` 来处理表单。#### 创建表单```typescript
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';@Component({selector: 'app-reactive-form',templateUrl: './reactive-form.component.html'
})
export class ReactiveFormComponent implements OnInit {form: FormGroup;constructor(private fb: FormBuilder) {}ngOnInit() {this.form = this.fb.group({name: ['', Validators.required],email: ['', [Validators.required, Validators.email]],password: ['', [Validators.required, Validators.minLength(6)]]});}onSubmit() {if (this.form.valid) {console.log('Form Data:', this.form.value);} else {console.log('Form is invalid');}}
}
表单模板
<form [formGroup]="form" (ngSubmit)="onSubmit()"><div><label for="name">Name:</label><input type="text" id="name" formControlName="name"><div *ngIf="form.get('name').invalid && form.get('name').touched">Name is required</div></div><div><label for="email">Email:</label><input type="email" id="email" formControlName="email"><div *ngIf="form.get('email').invalid && form.get('email').touched">Enter a valid email</div></div><div><label for="password">Password:</label><input type="password" id="password" formControlName="password"><div *ngIf="form.get('password').invalid && form.get('password').touched">Password must be at least 6 characters long</div></div><button type="submit">Submit</button>
</form>

十六、路由

Angular 的路由模块允许你在应用中定义导航路径。

1. 设置路由

配置路由
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';const routes: Routes = [{ path: '', component: HomeComponent },{ path: 'about', component: AboutComponent }
];@NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule]
})
export class AppRoutingModule { }
导航链接
<nav><a routerLink="/">Home</a><a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>

2. 路由守卫

路由守卫用于保护路由,确保用户具有访问权限。

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';@Injectable({providedIn: 'root'
})
export class AuthGuard implements CanActivate {constructor(private authService: AuthService, private router: Router) {}canActivate(next: ActivatedRouteSnapshot,state: RouterStateSnapshot): boolean {if (this.authService.isLoggedIn()) {return true;} else {this.router.navigate(['/login']);return false;}}
}
使用路由守卫
const routes: Routes = [{ path: '', component: HomeComponent },{ path: 'about', component: AboutComponent, canActivate: [AuthGuard] }
];

十七、国际化

Angular 提供了内置的国际化支持,用于多语言应用程序。

1. 准备翻译文件

创建翻译文件 messages.xlf

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2"><file source-language="en" datatype="plaintext" original="ng2.template"><body><trans-unit id="homeTitle" datatype="html"><source>Home</source><target>Accueil</target></当然,我将继续介绍更多关于 Angular 的内容,包括国际化的详细步骤、服务端渲染、以及一些常用的开发工具和资源。## 十七、国际化(继续)### 1. **准备翻译文件**创建翻译文件 `messages.xlf`:```xml
<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2"><file source-language="en" datatype="plaintext" original="ng2.template"><body><trans-unit id="homeTitle" datatype="html"><source>Home</source><target>Accueil</target></trans-unit><trans-unit id="aboutTitle" datatype="html"><source>About</source><target>À propos</target></trans-unit></body></file>
</xliff>

2. 配置 Angular

angular.json 中添加国际化配置:

{"$schema": "./node_modules/@angular/cli/lib/config/schema.json","projects": {"your-project-name": {"i18n": {"sourceLocale": "en","locales": {"fr": "src/locale/messages.fr.xlf"}},...}}
}

3. 标记可翻译文本

使用 Angular 内置的 i18n 属性标记可翻译的文本:

<h1 i18n="homeTitle">Home</h1>
<p i18n="aboutTitle">About</p>

4. 构建多语言版本

使用 Angular CLI 构建多语言版本:

ng build --localize

十八、服务端渲染(SSR)

Angular Universal 是一个用于实现 Angular 应用服务端渲染的库。

1. 安装 Angular Universal

ng add @nguniversal/express-engine

2. 更新应用模块

更新 app.server.module.ts 以适配服务端渲染:

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';@NgModule({imports: [AppModule,ServerModule],bootstrap: [AppComponent]
})
export class AppServerModule {}

3. 更新服务器文件

配置 server.ts 文件以启动 Express 服务器:

import 'zone.js/node';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync } from 'fs';import { AppServerModule } from './src/main.server';// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {const server = express();const distFolder = join(process.cwd(), 'dist/your-project-name/browser');const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';server.engine('html', ngExpressEngine({bootstrap: AppServerModule,}));server.set('view engine', 'html');server.set('views', distFolder);// Serve static files from /browserserver.get('*.*', express.static(distFolder, {maxAge: '1y'}));// All regular routes use the Universal engineserver.get('*', (req, res) => {res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });});return server;
}function run(): void {const port = process.env.PORT || 4000;// Start up the Node serverconst server = app();server.listen(port, () => {console.log(`Node Express server listening on http://localhost:${port}`);});
}// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
declare const __non_webpack_require__: NodeRequire;const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {run();
}export * from './src/main.server';

4. 运行 SSR

使用 Angular CLI 构建和运行 SSR 应用:

npm run build:ssr
npm run serve:ssr

相关文章:

全面分析一下前端框架Angular的来龙去脉,分析angular的技术要点和难点,以及详细的语法和使用规则,底层原理-小白进阶之路

Angular 前端框架全面分析 Angular 是一个由 Google 维护的开源前端框架。它最早在 2010 年发布&#xff0c;最初版本称为 AngularJS。2016 年&#xff0c;团队发布了一个完全重写的版本&#xff0c;称为 Angular 2&#xff0c;之后的版本&#xff08;如 Angular 4、Angular 5…...

VACUUM 剖析

VACUUM 剖析 为什么需要 Vacuum MVCC MVCC&#xff1a;Multi-Version Concurrency Control&#xff0c;即多版本并发控制。 PostgreSQL 使用多版本并发控制&#xff08;MVCC&#xff09;来支持高并发的事务处理&#xff0c;同时保持数据的一致性和隔离性。MVCC 是一种用于管…...

基于LangChain框架搭建知识库

基于LangChain框架搭建知识库 说明流程1.数据加载2.数据清洗3.数据切分4.获取向量5.向量库保存到本地6.向量搜索7.汇总调用 说明 本文使用openai提供的embedding模型作为框架基础模型&#xff0c;知识库的搭建目的就是为了让大模型减少幻觉出现&#xff0c;实现起来也很简单&a…...

LeetCode 1789, 6, 138

目录 1789. 员工的直属部门题目链接表要求知识点思路代码 6. Z 字形变换题目链接标签思路代码 138. 随机链表的复制题目链接标签思路代码 1789. 员工的直属部门 题目链接 1789. 员工的直属部门 表 表Employee的字段为employee_id&#xff0c;department_id和primary_flag。…...

Redis部署模式全解析:单点、主从、哨兵与集群

Redis是一个高性能的键值存储系统&#xff0c;以其丰富的数据结构和优异的读写性能而闻名。在实际应用中&#xff0c;根据业务需求的不同&#xff0c;Redis可以部署在多种模式下。本文将详细介绍Redis的四种主要部署模式&#xff1a;单点模式、主从复制模式、哨兵模式以及集群模…...

python-docx顺序读取word内容

来源How to use Python iteration to read paragraphs, tables and pictures in word&#xff1f; Issue #650 python-openxml/python-docx (github.com) from docx import Document from docx.oxml.ns import qndef iter_block_items(parent):"""生成 paren…...

kafka 集群原理设计和实现概述(一)

kafka 集群原理设计和实现概述(一) Kafka 集群的设计原理是为了实现高可用性、高吞吐量、容错性和可扩展性。以下是 Kafka 集群的设计原 理及其实现方法: 1. 分布式架构设计 Kafka 采用分布式架构,集群中的多个 Broker 共同工作,负责接收、存储和传递消息。通过将数据分布…...

three.js 第十一节 - uv坐标

// ts-nocheck // 引入three.js import * as THREE from three // 导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls // 导入lil.gui import { GUI } from three/examples/jsm/libs/lil-gui.module.min.js // 导入tween import * as T…...

git从master分支创建分支

1. 切换到主分支或你想从哪里创建新分支 git checkout master 2. 创建并切换到新的本地分支 develop git checkout -b develop 3. 将新分支推送到远程存储库 git push origin develop 4. 设置本地 develop 分支跟踪远程 develop 分支 git branch --set-upstream-toorigi…...

Chromium 调试指南2024 Mac篇 - 准备工作 (一)

1.引言 Chromium是一个由Google主导开发的开源浏览器项目&#xff0c;它为Google Chrome浏览器提供了基础框架。Chromium不仅是研究和开发现代浏览器技术的重要平台&#xff0c;还为众多其他基于Chromium的浏览器&#xff08;如Microsoft Edge、Brave等&#xff09;提供了基础…...

vue登陆密码加密,java后端解密

前端 安装crypto-js npm install crypto-js加密 //引入crypto-js import CryptoJS from crypto-js;/** ---密码加密 start--- */ const SECRET_KEY CryptoJS.enc.Utf8.parse("a15q8f6s5s1a2v3s"); const SECRET_IV CryptoJS.enc.Utf8.parse("a3c6g5h4v9sss…...

npm 安装踩坑

1 网络正常&#xff0c;但是以前的老项目安装依赖一直卡住无法安装&#xff1f;哪怕切换成淘宝镜像 解决办法&#xff1a;切换成yarn (1) npm i yarn -g(2) yarn init(3) yarn install在安装的过程中发现&#xff1a; [2/4] Fetching packages... error marked11.1.0:…...

内容安全复习 6 - 白帽子安全漏洞挖掘披露的法律风险

文章目录 安全漏洞的法律概念界定安全漏洞特征白帽子安全漏洞挖掘面临的法律风险“白帽子”安全漏洞挖掘的风险根源“白帽子”的主体边界授权行为边界关键结论 安全漏洞的法律概念界定 可以被利用来破坏所在系统的网络或信息安全的缺陷或错误&#xff1b;被利用的网络缺陷、错…...

dp经典问题:爬楼梯

dp经典问题&#xff1a;爬楼梯 爬楼梯 三步问题。有个小孩正在上楼梯&#xff0c;楼梯有n阶台阶&#xff0c;小孩一次可以上1阶、2阶或3阶。实现一种方法&#xff0c;计算小孩有多少种上楼梯的方式。结果可能很大&#xff0c;你需要对结果模1000000007。 Step1: 识别问题 这…...

示例:推荐一个基于第三方QRCoder.Xaml封装的二维码显示控件

一、目的&#xff1a;基于第三方QRCoder.Xaml封装的二维码控件&#xff0c;为了方便WPF调用 二、效果如下 功能包括&#xff1a;背景色&#xff0c;前景色&#xff0c;中心图片设置和修改大小&#xff0c;二维码设置等 三、环境 VS2022 四、使用方式 1、安装nuget包&#xf…...

阿里云服务器618没想到这么便宜,买早了!

2年前&#xff0c;我买了个服务器&#xff0c;租用服务器&#xff08;ECS5&#xff09;和网络宽带&#xff08;1M&#xff09;&#xff0c;可以说是非常非常低的配置了。 当时5年的折扣力度最大&#xff0c;但是打完折后&#xff0c;价格依然要近3000多元。 最近看到阿里云618活…...

提升Python技能的七个函数式编程技巧

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 递归📝 结构化模式匹配📝 不变性📝 纯函数📝 高阶函数📝 函数组合📝 惰性求值⚓️ 相关链接 ⚓️📖 介绍 📖 在现代编程中,虽然Python并不是一门纯粹的函数式编程语言,但函数式编程(Funct…...

微型操作系统内核源码详解系列五(五):cm3下Pendsv切换任务上篇

系列一&#xff1a;微型操作系统内核源码详解系列一&#xff1a;rtos内核源码概论篇&#xff08;以freertos为例&#xff09;-CSDN博客 系列二&#xff1a;微型操作系统内核源码详解系列二&#xff1a;数据结构和对象篇&#xff08;以freertos为例&#xff09;-CSDN博客 系列…...

Django测试平台搭建学习笔记1

一安装 pip离线安装requests2.32.0所需要的依赖&#xff1a; : charset-normalizer<4,>2 (3.0.0b1) : idna<4,>2.5 (3.7) : urllib3<3,>1.21.1 (2.2.0) : certifi>2017.4.17 (2024.6.2) pip离线安装pytest8.2.0所需要的依赖&#xff1a; : iniconfig (2…...

本地离线模型搭建指南-RAG架构实现

搭建一个本地中文大语言模型&#xff08;LLM&#xff09;涉及多个关键步骤&#xff0c;从选择模型底座&#xff0c;到运行机器和框架&#xff0c;再到具体的架构实现和训练方式。以下是一个详细的指南&#xff0c;帮助你从零开始构建和运行一个中文大语言模型。 本地离线模型搭…...

【IPython 使用技巧整理】

IPython 使用技巧整理 IPython 是一个交互式 Python 解释器&#xff0c;比标准 Python 解释器提供了更加强大的功能和更友好的使用体验。它为数据科学、机器学习和科学计算提供了强大的工具&#xff0c;是 Python 开发人员不可或缺的工具之一。本文将深入探讨 IPython 的各种使…...

什么是孪生素数猜想

什么是孪生素数猜想 素数p与素数p2有无穷多对 孪生素数的公式&#xff08;详见百度百科&#xff1a;孪生素数公式&#xff09; 利用素数的判定法则&#xff0c;可以得到以下的结论&#xff1a;“若自然数q与q2都不能被任何不大于的素数 整除&#xff0c;则q与q 2都是素数”…...

Python学习笔记16:进阶篇(五)异常处理

异常 在编程中&#xff0c;异常是指程序运行过程中发生的意外事件&#xff0c;这些事件通常中断了正常的指令流程。它们可能是由于错误的输入数据、资源不足、非法操作或其他未预料到的情况引起的。Python中&#xff0c;当遇到这类情况时&#xff0c;会抛出一个异常对象&#…...

Mac 安装依赖后依旧报错 ModuleNotFoundError: No module named ‘Crypto‘

ModuleNotFoundError: No module named ‘Crypto’ 解决办法 pip uninstall pycryptodome pip uninstall pycrypto pip uninstall crypto pip install pycrypto...

【07】持久化-数据库选择和设计

1. 数据库选择 在比特币原始论文中,并没有提到要使用哪一个具体的数据库,它完全取决于开发者如何选择。Bitcoin Core ,最初由中本聪发布,现在是比特币的一个参考实现,它使用的是 LevelDB。 我们将要使用的是BoltDB。Bolt DB是一个纯键值存储的 Go 数据库。没有具体的数据…...

压力测试

1.什么是压力测试 压力测试考察当前软硬件环境下系统所能承受的最大负荷并帮助找出系统瓶颈所在。压测都是为了系统在线上的处理能力和稳定性维持在一个标准范围内&#xff0c;做到心中有数 使用压力测试&#xff0c;我们有希望找到很多种用其他测试方法更难发现的错误&#…...

C语言| 数组元素的删除

同数组元素的插入差不多。 数组元素的插入&#xff0c;是先移动要插入元素位置后面的所有元素&#xff0c;再插入新元素&#xff0c;长度1。 C语言| 数组的插入-CSDN博客 数组元素的删除&#xff0c;是先删除元素&#xff0c;再把后面的元素往前移动一位&#xff0c;而本程序…...

QListView、QTableView或QTreeView截取滚动区域(截长图)

本文以QTreeView为例,理论上继承自QAbstractScrollArea的类都支持本文所述的方法。 一.效果 一共5个文件夹,每个文件文件夹下有5个文件,先把文件夹展开,然后截图。将滚动条拖到居中位置,是为了证明截图对滚动条无影响 下面是截的图 二.原理 将滚动区域的viewport设置为…...

论文《Tree Decomposed Graph Neural Network》笔记

【TDGNN】本文提出了一种树分解方法来解决不同层邻域之间的特征平滑问题&#xff0c;增加了网络层配置的灵活性。通过图扩散过程表征了多跳依赖性&#xff08;multi-hop dependency&#xff09;&#xff0c;构建了TDGNN模型&#xff0c;该模型可以灵活地结合大感受场的信息&…...

控制下属很简单,用好这3大管人绝招,再跳的刺头也不敢造次

控制下属很简单&#xff0c;用好这3大管人绝招&#xff0c;再跳的刺头也不敢造次 第一招&#xff1a;给压力 很多团队中的员工都是自己不带脑子工作&#xff0c;遇事就喜欢请示领导&#xff0c;让领导拿方案、拿决策。 还有一些人&#xff0c;推一下&#xff0c;他才动一下&a…...

2.APP测试-安卓adb抓取日志

1.打开手机的开发者模式&#xff0c;打开USB调试 &#xff08;1&#xff09;小米手机打开开发者模式&#xff1a; 【设置】-【我的设备】-【全部参数信息】-快速多次点击【OS版本】-进入开发者模式 &#xff08;2&#xff09;连接手机和电脑&#xff0c;手机打开USB调试 【设置…...

高考填报志愿选专业,要善于发掘自身优势

每年的高考季&#xff0c;如何填报志愿又再成为困扰家长以及学生的难题&#xff0c;可能在面对大量的专业时&#xff0c;无论是考生还是家长都不知道应该如何选择&#xff0c;好的专业孩子不一定有优势&#xff0c;感兴趣的冷门专业又担心日后找工作难。 实际上&#xff0c;专业…...

如何在 Ubuntu 14.04 上使用 HAProxy 实现 SSL 终止

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 简介 HAProxy&#xff0c;全称高可用代理&#xff0c;是一款流行的开源软件 TCP/HTTP 负载均衡器和代理解决方案&#xff0c;可在 Linu…...

dockercompose

安装dockerconpose #上传docker-compose安装包 chmod x docker-compose mv docker-compose /usr/bin/ [rootlocalhost ~]# docker-compose --version docker-compose version 1.24.1, build 4667896b文件格式以及编写注意事项 YAML 是一种标记语言&#xff0c;它可以很直观的…...

「51媒体」活动会议,展览展会,直播曝光的一种方法

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 我们在做活动会议&#xff0c;或者参加展览展会&#xff0c;需要进行直播的时候&#xff0c;可以通过一键同步多个媒体平台的方法&#xff0c;来扩大曝光&#xff0c;比如一场直播我们可…...

Go WebSocket入门+千万级别弹幕系统架构设计

Go实现WebSocket&#xff08;千万级别弹幕系统架构设计&#xff09; 1 websocket简介(基于HTTP协议的长连接) 使用WebSocket可以轻松的维持服务器端长连接&#xff0c;其次WebSocket是架构在HTTP协议之上的&#xff0c;并且也可以使用HTTPS方式&#xff0c;因此WebSocket是可靠…...

uniapp使用伪元素实现气泡

uniapp使用伪元素实现气泡 背景实现思路代码实现尾巴 背景 气泡效果在开发中使用是非常常见的&#xff0c;使用场景有提示框&#xff0c;对话框等等&#xff0c;今天我们使用css来实现气泡效果。老规矩&#xff0c;先看下效果图&#xff1a; 实现思路 其实实现这个气泡框的…...

字节跳动:从梦想之芽到参天大树

字节跳动掌舵人&#xff1a;张一鸣 2012年&#xff1a;梦想的起点&#xff1a;在一个阳光明媚的早晨&#xff0c;北京的一座普通公寓里&#xff0c;一位名叫张一鸣的年轻人坐在电脑前&#xff0c;眼中闪烁着坚定的光芒。他的心中有一个梦想——通过技术改变世界&#xff0c;让…...

组合数学、圆排列、离散数学多重集合笔记

自用 如果能帮到您&#xff0c;那也值得高兴 知识点 离散数学经典题目 多重集合组合 补充容斥原理公式 隔板法题目 全排列题目&#xff1a;...

网络技术原理需要解决的5个问题

解决世界上任意两台设备时如何通讯的&#xff1f;&#xff1f; 第一个问题&#xff0c;pc1和pc3是怎么通讯的&#xff1f; 这俩属于同一个网段&#xff0c;那么同网段的是怎么通讯的&#xff1f; pc1和pc2属于不同的网段&#xff0c;第二个问题&#xff0c;不同网段的设备是…...

【数据结构】链表的大概认识及单链表的实现

目录 一、链表的概念及结构 二、链表的分类 三、单链表的实现 建立链表的节点&#xff1a; 尾插——尾删&#xff1a; 头插——头删&#xff1a; 查找&#xff1a; 指定位置之后删除——插入&#xff1a; 指定位置之前插入——删除指定位置&#xff1a; 销毁链表&am…...

国企:2024年6月中国移动相关招聘信息 二

在线营销服务中心-中国移动通信有限公司在线营销服务中心 硬件工程师 工作地点:河南省-郑州市 发布时间 :2024-06-18 截至时间: 2024-06-30 学历要求:本科及以上 招聘人数:1人 工作经验:3年 岗位描述 1.负责公司拾音器等音视频智能硬件产品全过程管理,包括但…...

Elasticsearch:智能 RAG,获取周围分块(二)

在之前的文章 “Elasticsearch&#xff1a;智能 RAG&#xff0c;获取周围分块&#xff08;一&#xff09; ” 里&#xff0c;它介绍了如何实现智能 RAG&#xff0c;获取周围分块。在那个文章里有一个 notebook。为了方便在本地部署的开发者能够顺利的运行那里的 notebook。在本…...

华为---RIP路由协议的汇总

8.3 RIP路由协议的汇总 8.3.1 原理概述 当网络中路由器的路由条目非常多时&#xff0c;可以通过路由汇总(又称路由汇聚或路由聚合)来减少路由条目数&#xff0c;加快路由收敛时间和增强网络稳定性。路由汇总的原理是&#xff0c;同一个自然网段内的不同子网的路由在向外(其他…...

Python基础——字符串常见用法:切片、去空格、替换、拼接

文章目录 专栏导读1、拼接字符串2、获取字符串长度3、字符串切片4、字符串替换&#xff1a;5、字符串分割6、字符串查找7、字符串大小写转换8、字符串去除空白9、字符串格式化&#xff1a;10、字符串编码与解码&#xff1a;11、字符串判断12、字符串填充与对齐总结 专栏导读 &a…...

LeetCode.51N皇后详解

问题描述 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案…...

计算机网络之奇偶校验码和CRC冗余校验码

今天我们来看看有关于计算机网络的知识——奇偶校验码和CRC冗余校验码&#xff0c;这两种检测编码的方式相信大家在计算机组成原理当中也有所耳闻&#xff0c;所以今天我就来跟大家分享有关他们的知识。 奇偶校验码 奇偶校验码是通过增加冗余位使得码字中1的个数恒为奇数或偶数…...

二叉树经典OJ练习

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 二叉树经典OJ练习 收录于专栏【数据结构初阶】 本专栏旨在分享学习数据结构学习的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 前置说…...

【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】008 - make distclean 命令解析

【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】008 - make distclean 命令解析 一、make V=1 distclean 命令解析系列文章汇总:《【OpenHarmony4.1 之 U-Boot 源码深度解析】000 - 文章链接汇总》 本文链接:《【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】008 - mak…...

QTreeView双击任意列展开

一.效果 二.原理 重点是如何通过其他列的QModelIndex(假设为index),获取第一列的QModelIndex(假设为firstColumnIndex)。代码如下所示: QModelIndex firstColumnIndex = model->index(index.row(), 0, index.parent()); 这里要注意index函数的第三个参数,第三个参…...

Symfony服务容器的深度解析与应用

引言 Symfony是一个高度灵活的PHP框架&#xff0c;为开发复杂的web应用提供了丰富的工具和组件。服务容器是Symfony框架的核心组件之一&#xff0c;它负责管理类的依赖关系和生命周期。本文将详细探讨如何在Symfony中使用服务容器&#xff0c;包括服务的定义、注入和获取。 S…...

【高考志愿】建筑学

目录 一、专业介绍 1.1 专业定义 1.2 专业培养目标 1.3 核心课程 二、就业方向和前景 2.1 就业方向 2.2 专业前景 三、报考注意 四、行业趋势与未来展望 五、建筑学专业排名 一、专业介绍 1.1 专业定义 建筑学&#xff0c;这一充满艺术与科技魅力的学科&#xff0c;…...

C++ 左值右值 || std::move() || 浅拷贝,深拷贝 || 数据类型

数据类型&#xff1a; 作用&#xff1a;决定变量所占内存空间的字节大小&#xff0c;和布局方式基本数据类型&#xff1a; 算数类型&#xff1a; 整形&#xff08;bool / char……扩展集 / int / long……&#xff09;&& 浮点形&#xff08;float/double……&#xff…...

JavaFX布局-BorderPane

JavaFX布局-BorderPane 实现方式Java实现FXML实现 综合案例 将容器空间分成五个区域&#xff1a;顶部&#xff08;Top&#xff09;、底部&#xff08;Bottom&#xff09;、左侧&#xff08;Left&#xff09;、右侧&#xff08;Right&#xff09;和中心&#xff08;Center&#…...

【漏洞复现】Atlassian Confluence RCE(CVE-2023-22527)

产品简介 Atlassian Confluence 是一款由Atlassian开发的企业团队协作和知识管理软件&#xff0c;提供了一个集中化的平台&#xff0c;用于创建、组织和共享团队的文档、知识库、项目计划和协作内容。是面向大型企业和组织的高可用性、可扩展性和高性能版本。 0x02 漏洞概述 …...

.npmrc配置文件

.npmrc配置文件 .npmrc 是一个用于配置 npm 行为的文件。这个文件可以位于多个地方&#xff0c;但最常见的是位于项目目录或者你的用户主目录。npmrc文件由一系列键值对组成&#xff0c;用于配置npm在执行命令时的行为和参数。 一个 .npmrc 文件的例子可能包含以下内容&#…...

香港优才计划找中介是否是智商税,靠谱中介又该如何找?

关于香港优才计划的申请&#xff0c;找中介帮助还是自己DIY&#xff0c;网络上充斥的声音太多&#xff0c;对不了解的人来说&#xff0c;难以抉择的同时还怕上当受骗。 这其中很容易误导人的关键在于——信息差&#xff01; 今天这篇文章的目的就是想让大家看清一些中介和DIY…...

什么是React?

01 Why React? What is React? I think the one-line description of React on its home page (https://react.dev/) is concise and accurate: “A JavaScript library for building user interfaces.” 我认为React主页(https://react.dev/)上的一行描述既简洁又准确: …...

7. 核心功能(Core Features)

7. 核心功能&#xff08;Core Features&#xff09; 本章节深入介绍 Spring Boot 的详细信息。在这里&#xff0c;你可以了解想要使用的和自定义的主要功能。如果您还没有阅读 “Getting Started” 和 “Developing with Spring Boot” 这两节内容&#xff0c;不放先去阅读这两…...

数据结构 | 详解二叉树——堆与堆排序

&#x1f95d;堆 堆总是一棵完全二叉树。 大堆&#xff1a;父节点总是大于子节点。 小堆&#xff1a;父节点总是小于子节点。 注意&#xff1a;1.同一个节点下的两个子节点并无要求先后顺序。 2.堆可以是无序的。 &#x1f349;堆的实现 &#x1f334;深度剖析 1.父节点和子…...

python class __getattr__ 与 __getattribute__ 的区别

在Python中&#xff0c;__getattr__是一个特殊的方法&#xff0c;用于处理访问不存在的属性时的行为。它通常在类中被重写&#xff0c;以便在属性访问失败时提供自定义的处理逻辑。 __getattr__ 的使用 1. 基本用法 __getattr__方法在访问类实例的某个不存在的属性时自动调用…...

mysql内存和磁盘的关系

mysql内存和磁盘的关系 1.MySQL的内存和磁盘之间的关系是密切的。MySQL的数据存储在磁盘上&#xff0c;但为了高效地执行查询操作&#xff0c;它也会将数据页&#xff08;每个页通常为16KB&#xff09;读入内存。MySQL的缓冲池&#xff08;buffer pool&#xff09;是在内存中的…...