我正在使用Angular 5,我注意到很多重复的HTTP调用。在一个例子中,我得到一些参考数据,几乎不会改变。我试图尽可能多地重用这些调用,但似乎无法阻止正在进行的调用。我正在使用Jasmine测试来显示问题。
我试过import { Injectable } from "@angular/core";
import { TestBed } from "@angular/core/testing";
import { HttpClient } from "@angular/common/http";
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
@Injectable()
class ApiService {
constructor(private readonly http: HttpClient) {
}
getValue = () => this.http.get("").map(x => x).shareReplay(1);
}
describe("ApiService",
() => {
let apiService: ApiService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [],
imports: [HttpClientTestingModule],
providers: [ApiService]
}).compileComponents();
apiService = TestBed.get(ApiService);
httpMock = TestBed.get(HttpTestingController);
});
it("getValue for api called twice makes one call",
() => {
apiService.getValue().subscribe(x => expect(x).toBe(1));
apiService.getValue().subscribe(x => expect(x).toBe(1));
httpMock.expectOne("").flush(1); // Error: Expected one matching request for criteria "Match URL: ", found 2 requests.
});
});
:
import { Injectable } from "@angular/core";
import { TestBed } from "@angular/core/testing";
import { HttpClient } from "@angular/common/http";
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { Observable } from "rxjs/Observable";
import { Subject } from "rxjs/Subject";
import { ReplaySubject } from "rxjs/ReplaySubject";
import "rxjs/add/operator/map"
declare type GetDataHandler<T> = () => Observable<T>;
export class Cacheable<T> {
protected data: T;
protected subjectData: Subject<T>;
protected observableData: Observable<T>;
public getHandler: GetDataHandler<T>;
constructor() {
this.subjectData = new ReplaySubject(1);
this.observableData = this.subjectData.asObservable();
}
public getData(): Observable<T> {
if (!this.getHandler) {
throw new Error("getHandler is not defined");
}
if (!this.data) {
this.getHandler().map((r: T) => {
this.data = r;
return r;
}).subscribe(
result => this.subjectData.next(result),
err => this.subjectData.error(err)
);
}
return this.observableData;
}
public resetCache(): void {
this.data = null;
}
public refresh(): Observable<T> {
this.resetCache();
return this.getData();
}
}
@Injectable()
class CacheableApiService {
private serverList = new Cacheable<any>();
constructor(private readonly http: HttpClient) {
this.serverList.getHandler = () => this.http.get("").map(x => x).shareReplay(1);
}
getValue = () => this.serverList.getData();
}
describe("CacheableApiService",
() => {
let cacheableApiService: CacheableApiService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [],
imports: [HttpClientTestingModule],
providers: [CacheableApiService]
}).compileComponents();
cacheableApiService = TestBed.get(CacheableApiService);
httpMock = TestBed.get(HttpTestingController);
});
it("getValue called twice makes one call",
() => {
cacheableApiService.getValue().subscribe(x => expect(x).toBe(1));
cacheableApiService.getValue().subscribe(x => expect(x).toBe(1));
httpMock.expectOne("").flush(1); // Error: Expected one matching request for criteria "Match URL: ", found 2 requests.
});
});
我尝试过缓存
desc "Update the deployed code."
task :update_code
execute "/usr/bin/git pull origin #{fetch(:release_path)}")
end
end
答案 0 :(得分:1)
在这些情况下,您遇到的问题是您正在创建一个缓存的流两次。
如果你把你的测试重写为这样,我希望它会过去。
it("getValue for api called twice makes one call",
() => {
const stream = apiService.getValue();
stream.subscribe(x => expect(x).toBe(1));
stream.subscribe(x => expect(x).toBe(1));
httpMock.expectOne("").flush(1); // should work now
});
如果希望方法在每次调用时返回相同的流,那么这是一个与流无关的问题。你只想记住这个功能 - 有很多方法可以做到这一点!这是一个完全天真的方法:
@Injectable()
class ApiService {
private source: Observable<any>; // horrible typing, please don't do this for real
constructor(private readonly http: HttpClient) {}
getValue = () => {
if ( !this.source ) {
this.source = this.http.get("").map(x => x).shareReplay(1);
}
return this.source;
}
}
您可能还有兴趣将流设置为属性并直接使用它,而不是尝试从方法返回它。由于流是“懒惰的”,因此您不需要将功能提供给您的消费者。