从服务返回对象数组,直接从 observable
Returning object array from service, directly from observable
我对 TypeScript 和 RxJS 还很陌生,所以我对可观察对象和订阅的理解有限。
我需要从服务 class 调用一个方法,该方法 returns 一个对象数组(现在,它被记录到控制台),我将在单击按钮后的组件 class。
我 运行 遇到的问题是,当我尝试将数组分配给变量时,数组在控制台中返回为空。但是,当我直接记录 http.get 方法的结果时,我看到了我的对象数组。
我想知道我在这里忽略了什么会导致这种错误,我该怎么做才能修复它以避免 运行 再次出现这种情况?
cars.model.ts
export interface ICar {
Make: string;
Model: string;
Year: string;
Specifications: boolean[];
}
cars.new.mock.json
[
{
"Make": "Honda",
"Model": "CRV",
"Year": "2021",
"Specifications": [
true,
true,
false,
true,
false
]
},
{
"Make": "Toyota",
"Model": "Camry",
"Year": "2021",
"Specifications": [
true,
true,
false,
true,
false
]
}
]
app.component.html
<h1>{{title}}</h1>
<button (click)="shownewCars()">New Cars</button>
app.component.ts
import { Component, OnInit } from '@angular/core';
import { CarsService } from './services/cars.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
title = 'AutoZone';
constructor(private carsService: CarsService){
}
ngOnInit(): void {
}
shownewCars(){
this.carsService.logNewCarsMessage();
console.log(this.carsService.returnNewCars());
}
}
cars.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from "@angular/core";
import { ICar } from '../models/cars.model';
@Injectable({
providedIn: 'root'
})
export class CarsService{
carsURL = '/assets/cars.mock.json';
newCarsURL = '/assets/cars.new.mock.json'
private newCars: ICar[] = [];
constructor(private http : HttpClient){}
returnNewCars(): ICar[]{
this.http.get<ICar[]>(this.newCarsURL).subscribe(result => {this.newCars = result});
return this.newCars;
}
logNewCarsMessage(){
this.http.get(this.newCarsURL).subscribe((responseData) => console.log("Console log New Cars: ", responseData));
}
}
控制台
[]
Console log New Cars: (2)[{...}, {...}]
您的问题与异步代码有关。
http.get(...)
函数 return 是一个 Observable<ICar[]>
,订阅后将发送实际的 HTTP 请求。
这里的问题是代码没有等到 HTTP 响应从服务器返回。 .subscribe(result => {this.newCars = result})
注册应在 HTTP 调用 return 秒后执行的回调函数,但无需实际等待即可立即继续。
下一行立即 return 是(在那一刻)仍然是空的 this.newCars
变量。
logNewCarsMessage
函数之所以起作用,是因为该函数仅在 HTTP 响应到达后才记录。正如您在控制台输出中所见,Console log New Cars: (2)[{...}, {...}]
行在 []
之后打印 ,而您调用 logNewCarsMessage
函数 之前 returnNewCars
.
有两种方法可以解决这个问题:使用 Promises,或者最好使用 Observables。
RxJS 可观察对象
不是直接 return 汽车数组,return 一个最终会发出汽车数组的 Observable。
cars.service.ts
private newCars$: Observable<ICar[]>;
returnNewCars(): Observable<ICar[]> {
this.newCars$ = this.http.get<ICar[]>(this.newCarsURL);
return this.newCars$;
}
newCars$
中的 $ 符号不是必需的,但它是一个很好的约定,表示该变量实际上是一个 Observable。
app.component.ts
shownewCars(): void {
this.carsService.returnNewCars().subscribe(cars => console.log(cars));
}
承诺
您可以使用 .toPromise()
函数将 Observable 转换为 Promise。这样你就可以使用正常的 async/await 语法以同步的方式使用你的异步代码。
同样,我真的不推荐这种方式,因为虽然乍一看它可能看起来更容易,但它的功能要弱得多,而且 不是 Angular 或 RxJS 方式。
cars.service.ts
private newCars: ICar[] = [];
async returnNewCars(): Promise<ICar[]> {
this.newCars = await this.http.get<ICar[]>(this.newCarsURL).toPromise();
return this.newCars;
}
app.component.ts
async shownewCars(): Promise<void> {
const cars = await this.carsService.returnNewCars();
console.log(cars);
}
我对 TypeScript 和 RxJS 还很陌生,所以我对可观察对象和订阅的理解有限。
我需要从服务 class 调用一个方法,该方法 returns 一个对象数组(现在,它被记录到控制台),我将在单击按钮后的组件 class。
我 运行 遇到的问题是,当我尝试将数组分配给变量时,数组在控制台中返回为空。但是,当我直接记录 http.get 方法的结果时,我看到了我的对象数组。
我想知道我在这里忽略了什么会导致这种错误,我该怎么做才能修复它以避免 运行 再次出现这种情况?
cars.model.ts
export interface ICar {
Make: string;
Model: string;
Year: string;
Specifications: boolean[];
}
cars.new.mock.json
[
{
"Make": "Honda",
"Model": "CRV",
"Year": "2021",
"Specifications": [
true,
true,
false,
true,
false
]
},
{
"Make": "Toyota",
"Model": "Camry",
"Year": "2021",
"Specifications": [
true,
true,
false,
true,
false
]
}
]
app.component.html
<h1>{{title}}</h1>
<button (click)="shownewCars()">New Cars</button>
app.component.ts
import { Component, OnInit } from '@angular/core';
import { CarsService } from './services/cars.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
title = 'AutoZone';
constructor(private carsService: CarsService){
}
ngOnInit(): void {
}
shownewCars(){
this.carsService.logNewCarsMessage();
console.log(this.carsService.returnNewCars());
}
}
cars.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from "@angular/core";
import { ICar } from '../models/cars.model';
@Injectable({
providedIn: 'root'
})
export class CarsService{
carsURL = '/assets/cars.mock.json';
newCarsURL = '/assets/cars.new.mock.json'
private newCars: ICar[] = [];
constructor(private http : HttpClient){}
returnNewCars(): ICar[]{
this.http.get<ICar[]>(this.newCarsURL).subscribe(result => {this.newCars = result});
return this.newCars;
}
logNewCarsMessage(){
this.http.get(this.newCarsURL).subscribe((responseData) => console.log("Console log New Cars: ", responseData));
}
}
控制台
[]
Console log New Cars: (2)[{...}, {...}]
您的问题与异步代码有关。
http.get(...)
函数 return 是一个 Observable<ICar[]>
,订阅后将发送实际的 HTTP 请求。
这里的问题是代码没有等到 HTTP 响应从服务器返回。 .subscribe(result => {this.newCars = result})
注册应在 HTTP 调用 return 秒后执行的回调函数,但无需实际等待即可立即继续。
下一行立即 return 是(在那一刻)仍然是空的 this.newCars
变量。
logNewCarsMessage
函数之所以起作用,是因为该函数仅在 HTTP 响应到达后才记录。正如您在控制台输出中所见,Console log New Cars: (2)[{...}, {...}]
行在 []
之后打印 ,而您调用 logNewCarsMessage
函数 之前 returnNewCars
.
有两种方法可以解决这个问题:使用 Promises,或者最好使用 Observables。
RxJS 可观察对象
不是直接 return 汽车数组,return 一个最终会发出汽车数组的 Observable。
cars.service.ts
private newCars$: Observable<ICar[]>;
returnNewCars(): Observable<ICar[]> {
this.newCars$ = this.http.get<ICar[]>(this.newCarsURL);
return this.newCars$;
}
newCars$
中的 $ 符号不是必需的,但它是一个很好的约定,表示该变量实际上是一个 Observable。
app.component.ts
shownewCars(): void {
this.carsService.returnNewCars().subscribe(cars => console.log(cars));
}
承诺
您可以使用 .toPromise()
函数将 Observable 转换为 Promise。这样你就可以使用正常的 async/await 语法以同步的方式使用你的异步代码。
同样,我真的不推荐这种方式,因为虽然乍一看它可能看起来更容易,但它的功能要弱得多,而且 不是 Angular 或 RxJS 方式。
cars.service.ts
private newCars: ICar[] = [];
async returnNewCars(): Promise<ICar[]> {
this.newCars = await this.http.get<ICar[]>(this.newCarsURL).toPromise();
return this.newCars;
}
app.component.ts
async shownewCars(): Promise<void> {
const cars = await this.carsService.returnNewCars();
console.log(cars);
}