-1

I know there are many questions and answers based on Promise, but what I want to do is to retrieve some data with axios (to a microservice) and then to use this data in order to send another request (to a different microservice).

Somehow, I figured out how to set my request:

screenshot from console with the request right before axios call

The problem is that in backend I have only first two clauses. I think this is because I have used async/await in order to successfully avoid Promise and get the actual result/class. What I meant is that, maybe the request is sent before the promise is fulfilled, but how do I correctly get the request in console?

I am newbie into Javascript, so any helping hand is welcome.

EDIT:

Here is my code:

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();
            }
        });
}

The above one is the first call I've talked about.

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();
                }
            });
    };

I have the second call in last paragraph which calls the buildSearchObject method which contains our promise. As I told you I figured out how to send it as value, but I think that because of "asynchronicity" maybe my promise is not ready yet in the moment when second call is called, this is why my code has the promise in state.

EDIT 2:

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

Here is my constructor, where I create my this.state.servicesList.

  • 1
    you haven't shown us your code, so it's not possible for us to tell you what you're doing wrong.... but you want to make the first call, returning a Promise, then inside the resolve of that promise (which gets triggered when the first call completes) you make your second call. If you show us what you actually did (in text, not screenshots please) you'll get more direct answers. – Daniel Beck Nov 09 '21 at 20:15
  • 1
    Some misconceptions here. Using async/await doesn't avoid promises. Also, the need to wait for the result of one API before calling a 2nd API with info from the first result is not a novel use case at all (and there are many examples e.g. [here](https://stackoverflow.com/questions/44182951/axios-chaining-multiple-api-requests) and [here](https://stackoverflow.com/questions/47343225/making-2-sequential-requests-with-axios-second-request-depends-on-the-response)). – jarmod Nov 09 '21 at 20:28
  • You write `this.state.servicesList // here is the promise`, but it's not clear where you initialise that state property or where `getServicesList(…)` is called – Bergi Nov 10 '21 at 07:17

2 Answers2

1

Some advice:

  • Do not mix traditional promises syntax with async / await. It will make your code hard to understand, even for yourself. Do not mix either callback approach with promises. Choose one approach and stick to it.
  • If you are having a hard time with promises, force yourself to use async / await everywhere. async / await is easier to understand in my opinion, because it doesn't break your code flow.

For instance, transform this:

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

to:

try {
  const response = await FlowsInventoryAPI.searchServices(/* params */);
  /* response code */
} catch (error) {
  /* error code */
}
  • Do not make your constructors asynchronous like you do where you call this.getServicesList, because you cannot wait for an asynchronous operation (like getServicesList) inside a constructor. Use instead a static async method.

For instance, transform this:

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

to:

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;
  }
}

Instead of calling const object = new SomeObject(props);, do const object = await SomeObject.create(props);

Jean-Baptiste Martin
  • 1,399
  • 1
  • 10
  • 19
  • 1
    Better than having an `init` method on the instance would be to pass the `servicesList` as a constructor parameter (and calling a `static` `getServicesList()` from `create`), so you can't even construct an incomplete instance in the first place – Bergi Nov 10 '21 at 13:16
0

You will need to use await keyword to wait for a promise response before continuing.

  // 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

Kamaro
  • 955
  • 1
  • 10
  • 11