如何让 Javascript 在发送请求之前等待 Promise?

Posted

技术标签:

【中文标题】如何让 Javascript 在发送请求之前等待 Promise?【英文标题】:How to make Javascript wait for a Promise before sending a request? 【发布时间】:2021-12-22 12:44:02 【问题描述】:

我知道有很多基于 Promise 的问题和答案,但我想做的是用 axios 检索一些数据(到微服务),然后使用这些数据发送另一个请求(到不同的微服务)。

不知何故,我想出了如何设置我的请求:

screenshot from console with the request right before axios call

问题是在后端我只有前两个子句。我认为这是因为我使用了 async/await 来成功避免 Promise 并获得实际的结果/类。我的意思是,也许请求是在承诺完成之前发送的,但是我如何在控制台中正确获取请求?

我是 javascript 的新手,所以欢迎任何帮助。

编辑:

这是我的代码:

getServicesList = async (instanceIds) => 
    return await FlowsInventoryAPI.searchServices(instanceIds, this.props.salesline, this.props.environment, this.props.sources, this.props.targets)
        .then((response) => 
            return response;
        )
        .catch((error) => 
            Toastr.error(ResponseErrorProvider.getError(error));
            if (ResponseErrorProvider.isUnauthorized(error)) 
                Toastr.error(error.response.data.message);
                this.props.onLogout();
            
        );

以上是我谈到的第一个电话。

buildSearchObject = (size, page, status) => 
        let interval = TimestampUtils.getInterval(this.props.logsTimeInterval);
        let from = interval.from * 1000;
        let to = interval.to * 1000;
        
        return 
            fromMillis: from,
            toMillis: to,
            size: size,
            page: page,
            salesline: this.props.salesline,
            environment: this.props.environment,
            routes: this.props.routes,
            sources: this.props.sources,
            targets: this.props.targets,
            customFilters: [...this.props.filters.values(), ...this.getEnabledAdvancedFilters().values()],
            status: status === LogStatus.ALL ? "" : status,
            sortFieldName: this.props.sortColumn,
            order: this.props.sortOrder,
            searchFilter: this.props.searchFilter,
            searchFilterOperator: this.props.searchFilterOperator,
            applications: this.props.applications,
            openedStores: this.props.openedStores,
            servicesPromise: this.state.servicesList // here is the promise
        
    ;
searchLogs = (size, page, status, callback) => 
        loadingService.showLoadingModal("loadingLogsPage", this.props.location.pathname);
        let searchObject = this.buildSearchObject(size, page, status);
        ElasticSearchApi.search(searchObject, this.props.token)
            .then(response => 
                callback(response);
            )
            .catch((error) => 
                loadingService.hideLoadingModal("loadingLogsPage", this.props.location.pathname);
                Toastr.error(ResponseErrorProvider.getError(error));
                if (ResponseErrorProvider.isUnauthorized(error)) 
                    Toastr.error(error.response.data.message);
                    this.props.onLogout();
                
            );
    ;

我在最后一段中有第二个调用,它调用了包含我们承诺的 buildSearchObject 方法。正如我告诉你的那样,我想出了如何将它作为值发送,但我认为由于“异步性”,我的诺言可能在第二次调用时还没有准备好,这就是为什么我的代码有状态的诺言。

编辑 2:

 constructor(props) 
        super(props);
        this.ongoingRequestId = undefined;
        this.ongoingRequests = new Map();
        this.state = 
            servicesList: this.getServicesList(this.getInstanceIds())
        
    

这是我的构造函数,我在其中创建我的 this.state.servicesList。

【问题讨论】:

你没有向我们展示你的代码,所以我们不可能告诉你你做错了什么......但是你想打第一个电话,返回一个承诺,然后在该承诺的解决方案内(在第一次通话完成时触发),您进行第二次通话。如果您向我们展示您的实际操作(请以文字形式,而不是屏幕截图),您将获得更直接的答案。 这里有一些误解。使用 async/await 并不能避免 promise。此外,在使用第一个结果中的信息调用第二个 API 之前需要等待一个 API 的结果根本不是一个新颖的用例(并且有很多示例,例如 here 和 here)。 您写了this.state.servicesList // here is the promise,但不清楚您在哪里初始化该状态属性或在哪里调用getServicesList(…) 【参考方案1】:

您需要使用await 关键字等待承诺响应,然后再继续。

  // 1. Wait for create or update the customer before continuing
  const customerId = await updateOrCreateCustomer(customerData);

  // 2. Register sale, with customer created in previous section
  const customerSale = sale(paymentMethod, customerId);

Read more about the await keyword

【讨论】:

【参考方案2】:

一些建议:

不要将传统的 Promise 语法与 async / await 混用。它会让你的代码难以理解,即使是你自己。不要将任何一种回调方法与 Promise 混合使用。选择一种方法并坚持下去。 如果您在使用 Promise 时遇到困难,请强迫自己在任何地方都使用 async / await。我认为 async / await 更容易理解,因为它不会破坏您的代码流。

例如,转换这个:

FlowsInventoryAPI.searchServices(/* params */)
  .then((response) => /* response code */)
  .catch((error) => /* error code */)

到:

try 
  const response = await FlowsInventoryAPI.searchServices(/* params */);
  /* response code */
 catch (error) 
  /* error code */

不要像调用this.getServicesList 那样使构造函数异步,因为您不能等待构造函数内的异步操作(如getServicesList)。请改用静态异步方法。

例如,转换这个:

class SomeObject extends Something 
  constructor(props) 
    super(props);
    this.ongoingRequestId = undefined;
    this.ongoingRequests = new Map();
    this.state = 
      servicesList: this.getServicesList(this.getInstanceIds())
    
  

到:

class SomeObject extends Something 
  constructor(props) 
    super(props);
    this.ongoingRequestId = undefined;
    this.ongoingRequests = new Map();
    this.state =  servicesList: null ;
  

  async init() 
    this.state.servicesList = await this.getServicesList(this.getInstanceIds());
  

  static async create(props) 
    const someObject = new SomeObject(props);
    await someObject.init();
    return someObject;
  

不要调用const object = new SomeObject(props);,而是调用const object = await SomeObject.create(props);

【讨论】:

比在实例上使用init 方法更好的是传递servicesList 作为构造函数参数(并从create 调用static getServicesList()),这样您就可以' 甚至一开始就不构造一个不完整的实例 @Bergi 我同意!

以上是关于如何让 Javascript 在发送请求之前等待 Promise?的主要内容,如果未能解决你的问题,请参考以下文章

如何在使用 res.sendFile() 将请求发送回客户端之前等待文件创建完成

如何让任务在 Swift 3 中等待完成

如何等待此功能完成?

如何等待http请求在处理到angular 7中的下一步之前获得响应[重复]

在加载表单之前等待异步函数(Http 请求)

JavaScript之AjAX