Angular 按顺序处理请求

Angular 按顺序处理请求,angular,typescript,rxjs6,Angular,Typescript,Rxjs6,主要目标是按顺序处理我的请求。我有扫描仪快速扫描值的输入。但有时服务器返回数据的速度很慢,若我扫描得很快,服务器就会崩溃并返回500。我的想法是按顺序处理这个请求。我试图找到一些解决办法,但没有找到我想要的。我不知道我是否应该使用一些拦截器,或者将其保存在服务或组件中 我试图在拦截器中找到解决方案,但在那个里我并没有发现请求何时完成,拦截器可以处理下一个请求。我试着使用rxjs操作符,但我没有;I don’我不知道如何结合到我的解决方案中。这就是我想在解决方案中使用的示例 from([1, 2,

主要目标是按顺序处理我的请求。我有扫描仪快速扫描值的输入。但有时服务器返回数据的速度很慢,若我扫描得很快,服务器就会崩溃并返回500。我的想法是按顺序处理这个请求。我试图找到一些解决办法,但没有找到我想要的。我不知道我是否应该使用一些拦截器,或者将其保存在服务或组件中

我试图在拦截器中找到解决方案,但在那个里我并没有发现请求何时完成,拦截器可以处理下一个请求。我试着使用rxjs操作符,但我没有;I don’我不知道如何结合到我的解决方案中。这就是我想在解决方案中使用的示例

from([1, 2, 3, 4])
  .pipe(
    concatMap(param =>
      this.http.get(
        `http://localhost:6013/api/v1/test/buffer?data=${param}`
      )
    )
  )
  .subscribe(res => console.log(res));
从操作员处观察我的请求,并按顺序处理ConcatMap

这是我的骷髅应用程序

app.component.ts

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { FormBuilder, Validators } from '@angular/forms';
import { Subject } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  form = this.fb.group({
    input: ['', Validators.required]
  });

  makeRequest$ = new Subject();
  constructor(private http: HttpClient, private fb: FormBuilder) {}

  onSubmit() {
    this.http
      .get(
        `http://localhost:6013/api/v1/test/buffer?data=${
          this.form.controls.input.value
        }`
      )
      .subscribe(res => {
        console.log(res);
      });

    this.form.reset();
  }

  ngOnInit() {}
}
app.interceptor.ts

import { Injectable } from '@angular/core';
import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AppInterceptor implements HttpInterceptor {
  arrayRequest: Array<HttpRequest<any>> = [];

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(req);
  }
}
从'@angular/core'导入{Injectable};
进口{
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent
}来自“@angular/common/http”;
从“rxjs”导入{Observable};
@可注射()
导出类AppInterceptor实现HttpInterceptor{
arrayRequest:Array=[];
拦截(
请求:HttpRequest,
下一步:HttpHandler
):可见{
返回next.handle(req);
}
}
app.components.html

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <label>
    Data:
    <input type="text" formControlName="input" />
  </label>

  <button type="submit" [disabled]="!form.valid">Submit</button>
</form>

数据:
提交

我排除了上面类似代码的东西。ConcatMap按顺序处理请求,但我不知道我应该如何处理请求以及我应该如何选择方向。

我不是一个有棱角的人,但我会为您的问题提供一个简洁的Javascript解决方案。你的问题就是一个典型的例子。在Javascript中,a
Promise
是一个对象,它可能在将来某个时候产生一个值。如果你从未听说过这个概念,我相信上面的说法很难理解,但让我们用常识来思考。Javascript中的承诺与现实生活中的承诺没有什么不同。如果我向你保证,可能会发生以下情况:

  • 当我向你承诺的时候,我的承诺已经实现了,在这种情况下你可以处理它
  • 我的承诺将在将来的某个时候兑现
  • 将来很明显,我的诺言没有兑现
  • 我的承诺永远不会被评价
当您使用承诺时,这些直观的案例在编程中有类似的案例

承诺的例子:

new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000); // (*)

});

如您所见,Promise构造函数获得一个
函数
参数,该参数又有一个
解析
和一个
拒绝
参数。
解析
拒绝
都是
功能
<代码>解析在履行
承诺
时调用,而
拒绝
在拒绝
承诺
时调用。在我们的例子中,
Promise
的主体包含对
setTimeout
的调用,该调用确保
Promise
将在创建
Promise
后一秒解析

那么,如果一个请求是一个承诺(直觉上它是一个承诺,你会得到一个响应,不管它是什么),而下一个请求是下一个承诺,依此类推,该怎么办?有没有一种方法可以连锁承诺?当然,让我们看看完整的示例:

new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000); // (*)

}).then(function(result) { // (**)

  alert(result); // 1
  return result * 2;

}).then(function(result) { // (***)

  alert(result); // 2
  return result * 2;

}).then(function(result) {

  alert(result); // 4
  return result * 2;

});
正如您可能已经猜到的,您的请求应该包含在承诺的主体中,通过调用链接起来。例如:

function promiseBody(resolve, reject) {
    // send request
    // if successful, call resolve
    // if failed, call reject
}

var prom = new Promise(promiseBody); 

//this array contains requests to be called after the first
for (var req of requests) {
    prom = prom.then(promiseBody);
}
像这样把你的承诺链接起来是非常整洁的,很容易理解和维护。当然,这更像是一个理论上的答案,因为您需要定义什么是
解决
拒绝
承诺人
请求
在您的具体情况下看起来是相似的,并且您还需要处理其中一个请求因某种原因永远不会得到响应的可能情况,但一旦你明白了你有一个非常优雅的方法来进行,并且只需要弄清楚细节,你就会走上正确的道路

当然,您可以用传统的方法解决这个问题,通过链接回调,但这不是很优雅。您还可以使用Javascript生成器解决此问题,最终将得到比老式回调()解决方案更优雅的解决方案,如:

function *myRequestHandler(request) {
    while (request) {
        send(request);
        request = yield;
    };
}

并确保在调用时传递正确的
请求
,每当执行回调时,调用
next()
,传递
next
请求
,因为我理解您的问题,您需要在submit上顺序执行api请求在您的情况下,您需要rxjs主题来实现预期行为。我修改了您的组件,以便您可以查看ngOnInit和onSubmit函数

makeRequest$现在是可观察的,在每个 onSubmit方法调用。您可以使用concatMap按顺序发送api 请求,也可以使用延迟运算符暂停一段时间 请求完成后,服务器不会受到太多的攻击


另外,请看一下取消订阅$和takeUntil(this.unsubscribe$)我不确定我是否完全理解您的意图,但在我看来,拦截器在这方面没有用处
concatMap
确实会强制按顺序发出请求,因此您在这方面的做法是正确的。您的示例只是显示了用于驱动请求的表单输入-您的扫描代码是什么样子的?我猜代码将异步返回一个值,然后将该值输入到源可观察对象中,然后将该源可观察对象连接到http请求中。
import { Component, OnInit } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { FormBuilder, Validators } from "@angular/forms";
import { Subject } from "rxjs";
import { concatMap, takeUntil, delay } from "rxjs/operators";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"]
})
export class AppComponent implements OnInit {
  public form = this.fb.group({
    input: ["", Validators.required]
  });

  private makeRequest$ = new Subject();
  private unsubscribe$ = new Subject();

  constructor(private http: HttpClient, private fb: FormBuilder) {}

  ngOnInit() {
    this.makeRequest$
      .pipe(
        delay(500),
        concatMap(item =>
          this.http.get(`http://localhost:6013/api/v1/test/buffer?data=${item}`)
        ),
        takeUntil(this.unsubscribe$)
      )
      .subscribe();
  }

  ngOnDestroy(): void {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }

  public onSubmit() {
    this.makeRequest$.next(this.form.controls.input.value);
    this.form.reset();
  }
}