Angular和Observale:如何在给定时间内避免对API的多次请求

Chr*_*ler 8 javascript observable rxjs typescript angular

我在Angular 4应用中有类似的东西(出于示例的原因,我删除了代码)

@Injectable()
export class SomeService {

  constructor(
    private http: Http
    ) {
  }

  get(id: number) {
    return this.http.get('http://somedomain/somemodel/${id}.json');
  }

}
Run Code Online (Sandbox Code Playgroud)

一些组件使用它来进行API调用。

constructor(private someService: SomeService) {}
...
someMethod() {
  // code here...
  this.someService.get(2).subscribe( someHandlerFunction );
}

someOtherMethod() {
  // more code here...
  this.someService.get(2).subscribe( someHandlerFunction );
}
Run Code Online (Sandbox Code Playgroud)

问题是我不知道何时调用someMethod()和someOtherMethod()。有时可能会同时调用它们,然后,我的API将被调用两次。我要查找的是是否有任何方法可以更改我的服务以仅在X数量的时间后执行此请求。我尝试使用去抖动:

get(id: number) {
  return this.http.get(`http://somedomain/somemodel/${id}.json`).debounceTime(10000);
}
Run Code Online (Sandbox Code Playgroud)

期望(在这种情况下)此HTTP get请求将仅在10秒后重复,如果在10秒内发出请求,则该请求将不会重复,但是observable会发出最后一个值。但这没有用。有小费吗?

PS:我知道我可以使用某种标志来控制它,但是只要它不能很好地缩放,就不能这样做。我有许多带有许多HTTP请求的服务。

有什么想法吗?

小智 5

Debounce 应该用在调用 http 服务的 observable 上,而不是用在 http 请求本身上。所以例如:

someObservable
  .valueChanges
  .debounceTime(1000)
  .subscribe(// Call the http service here)
Run Code Online (Sandbox Code Playgroud)

此处对先前提出的问题提供了更好的解释。


Lan*_*ara 3

您可以使用 RxJS 缓存结果,然后设置一个间隔,每隔几秒清除一次缓存,从而允许发出新请求。当您不希望用户每次加载页面时都重新查询数据库时,尤其是没有添加任何新内容时,这通常是一个好方法。

这是一种比其他答案稍微冗长的方法,但它提供了一些好处:

  • 您正在缓存结果,限制服务器和数据库上的负载
  • 与仅使用其他答案不同debounceTime,您不仅仅是阻止请求。您正在阻止请求并提供缓存的结果。如果您只阻止请求,您将不会得到任何结果。通过我的方法,如果需要,您仍然可以获得结果,使用最后获取的结果 - 只是在您允许之前它不会发出新请求。

缓存结果:

Class ProjectService {
    private cachedProjects: Observable<Project[]>;

    all(): Observable<Project[]> {
        if (!this.cachedProjects) {
            this.cachedProjects = this.httpService.get(`${this.url}/project`)
                .map(res => res.data.map(project => new Project(project)))
                .publishReplay()
                .refCount();
        }

        return this.cachedProjects;
    }
}
Run Code Online (Sandbox Code Playgroud)

当您致电服务时:

this.projectService.all().subscribe((projects: Project[]) => {
    // 'projects' will be fetched the first time this is called, 
    // and any subsequent requests will use the 'cachedProjects'
    // stored in the service, until the interval sets it to null.
});
Run Code Online (Sandbox Code Playgroud)

现在,为了确保它仅偶尔阻止 HTTP 调用,您可以在服务上设置一个时间间隔。按如下方式修改您的服务:

Class ProjectService {
    private cachedProjects: Observable<Project[]>;

    constructor() {
        // Put this in a function or something.
        setInterval(() => {
            this.cachedProjects = null;
        }, 5000);
    }

    all(): Observable<Project[]> {
        if (!this.cachedProjects) {
            this.cachedProjects = this.httpService.get(`${this.url}/project`)
                .map(res => res.data.map(project => new Project(project)))
                .publishReplay()
                .refCount();
        }

        return this.cachedProjects;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以现在你可以每 5 秒发出一个新请求,否则将使用缓存的项目。