【问题标题】:How to make synchronous HTTP request in Angular 8 or 9 (make a request and wait)如何在 Angular 8 或 9 中发出同步 HTTP 请求(发出请求并等待)
【发布时间】:2020-09-29 10:14:37
【问题描述】:

共有三个按钮:

单击第一个Request HTTP Data As Promise 按钮将获得其HTTP 响应为Promise

第二个Request HTTP Data As Observable 按钮的响应为Observable

这两个按钮都使用异步响应机制获得响应。

现在,我希望第三个Request HTTP Data and Wait 按钮获得同步响应。我希望它等待 http 服务返回 HTTP 响应。

怎么可能呢?这里是 Stackblitz 项目的链接(请使用 HttpService 脚本中定义的占位符函数 getDataSynchronous 来实现此功能):

https://stackblitz.com/edit/angular-ivy-ukgwct?file=src%2Fapp%2Fhttp.service.ts

export class HttpService {
  jsonFile = '../assets/products.json';

  constructor(private http: HttpClient) {}

  getDataAsPromise(): Promise<any> {
    return this.http.get(this.jsonFile)
      .toPromise()
  }

  getDataAsObservable(): Observable<any> {
    return this.http.get(this.jsonFile)
  }

  getDataSynchronous(): any {
    return []
  }

【问题讨论】:

  • 但是为什么呢?它阻塞了唯一的线程。
  • 我只是想知道如何在 Angular 中做到这一点。

标签: angular typescript promise observable


【解决方案1】:

您可以尝试一个名为 ts-sync-request 的 typescript 库。

GitHub:https://github.com/VeritasSoftware/ts-sync-request

NPM:https://www.npmjs.com/package/ts-sync-request

您可以使用此库从 typescript 进行同步 http 调用。

例如:

获取

import { SyncRequestClient } from 'ts-sync-request/dist'
let id = 1;
let url = "http://localhost:59039/api/Movies/" + id;
 
let response = new SyncRequestClient()
                             .addHeader("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDc2OTg")
                        .get<Movie>(url);

【讨论】:

    【解决方案2】:

    虽然对于 Angular 来说不是惯用的,但从技术上讲,您可以使用 synchronous XHR request 来实现这一点:

    getDataSynchronous() {
        var request = new XMLHttpRequest();
        request.open('POST', `${environment.userApiUrl}/logout`, false);  // `false` 
        makes the request synchronous
        request.send({});
    
        if (request.status === 200) {
            return request.response;
        } else {
            throw new Error('request failed');
        }
    }
    

    请注意,它不能使用 Angular HTTP 客户端完成,并且除非绝对必要,否则不应使用此解决方案,因为主线程上的同步 XmlHttpRequestdeprecated in most modern browsers

    【讨论】:

    • 感谢您的帮助。我正在使用模拟离线开发,我需要同步读取文件以进行一些排序和过滤。
    • 我想指出,“只是不要这样做”的笼统声明不利于编程思维。想想一个前端应用程序,它的 api 是有状态的/无头的。您必须在许多请求之前发送请求以获取 CSRF 令牌。说“只是不这样做”意味着您将所有表单请求嵌套在回调中——这很丑陋、很麻烦,而且一般来说难以维护。我可以想到更多同步请求也完全可以接受的场景。一般来说,当然,不要走同步捷径。但是,在某些情况下它完全没问题。
    • @NateI 你的例子不是一个好例子。如果请求需要很长时间并且用户尝试在浏览器中切换选项卡怎么办?如果我想在请求进行时显示动画加载微调器怎么办?这些都不起作用,因为同步 HTTP 请求会阻塞浏览器的 UI 线程。如果可维护性是一个问题,我们可以使用async/await 来同步查看代码。 IMO 很难在 JavaScript 中找到同步 HTTP 请求是更好选择的场景。
    • 我的意思是,这已经被讨论过数千次了,无论如何都不是一个谜。在worker上调用同步请求不会阻塞UI线程或导致挂起/冻结,与async/await基本相同。该问题询问如何完成同步请求,而async/await同步的。对工作人员的同步请求也不是(在工作人员内部,因此等待完成的其他逻辑可能存在于那里并且真正是“同步的”),但你问了;)
    • @nate-i 公平点,我已经改写了答案。
    【解决方案3】:

    这对我有用。

    将此代码写入您的app.component.ts 文件中:

      ngOnInit(): void
      {
        window.addEventListener('beforeunload', (e) =>
        {
          this.logoutAndWait();
        })
      }
    
      async logoutAndWait()
      {
        const httpData = await this.userService.logoutSynchronous();
      }
    

    并创建一个如下所示的同步注销功能:

      logoutSynchronous()
      {
        return this.http.post<string>(`${environment.userApiUrl}/logout`, {}, { withCredentials: true }).toPromise()
      }
    

    【讨论】:

      【解决方案4】:

      Demo 异步函数是通过事件循环异步操作的函数,使用隐式 Promise 返回其结果。但是使用异步函数的代码的语法和结构更像是使用标准同步函数。 await 运算符用于等待 Promise。它只能在异步函数中使用。

      getDataSynchronous() {
          return  this.http.get(this.jsonFile).toPromise()
      }
      

      在组件中

      async requestDataAndWait() {
          let httpData = await this.http.getDataSynchronous();  
          this.addMessages(httpData)  
      }
      

      【讨论】:

      • 在这里分配data 或拥有await(因此async)毫无意义——这些都不会改变getDataSynchronous 不同步这一事实,实际上返回值的promise,因此可以实现getDataSynchronous() { return this.http.get(this.jsonFile).toPromise() }.
      • 这不会使其同步。 Observables 和 async 方法不是同步的,因此尝试互换它们是没有用的。在他们结束时,如果它在不久的将来或以后成功,你就会得到数据,如果不是,你就不会。最好将您的应用程序设计为异步的,然后利用这些异步性。
      【解决方案5】:

      你不能,不是用 Javascript。

      【讨论】:

        【解决方案6】:

        您可以通过使用 asyncawait 来完成此操作

        async getDataSynchronous() {
          let data = await this.http.get(this.jsonFile).toPromise();
          return data;
        }
        
        猜你喜欢
        • 1970-01-01
        • 2018-11-13
        • 2012-06-02
        • 1970-01-01
        • 2022-11-11
        • 2010-09-12
        • 1970-01-01
        • 2018-07-13
        • 1970-01-01
        相关资源
        最近更新 更多