Florian Donaubauer
Florian Donaubauer

Reputation: 23

javascript callback function synchronise

I am currently working on an Alexa Skill to collect data from an SAP system. Because of a callback in my function to collect the data, Alexa speaks, before the speakOutput variable gets updated.

const LagerhueteIntent = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' &&
            Alexa.getIntentName(handlerInput.requestEnvelope) === 'LagerhueteIntent';
    },
    handle(handlerInput) {
        let speakOutput;
        console.log("test");
        findWarehouseKeepers(function(warehouseKeeper) {
            console.log(warehouseKeeper);
            speakOutput = "Die Lagerhüter sind die Produkte mit den Ids" + warehouseKeeper;
            console.log(speakOutput);
        });
        return handlerInput.responseBuilder
            .speak(speakOutput)
            //.reprompt('add a reprompt if you want to keep the session open for the user to respond')
            .getResponse();
    }
};

With my function:

function findWarehouseKeepers(callback) {
    var args = getArgs();
    console.log(args);
    var Client = require('node-rest-client').Client;
    var client = new Client();

    client.get("http://XXXXXXXX$format=json", args, function(data, response) {
        let validValuesList = new List([]);
        data.d.results.forEach(function(data) {
            validValuesList.add(data.ProductId);
        });
        console.log(validValuesList);
        let validValuesAsArray = validValuesList.toArray();
        console.log(validValuesAsArray);
        callback(validValuesAsArray);
    });
}

How can I get my function synchronized, so the speakOutput variable gets updated before the next code gets executed? Thanks in advance.

Upvotes: 2

Views: 49

Answers (1)

Felix Kling
Felix Kling

Reputation: 816840

As per documentation, handle can return a promise, which will allow you to build the response once you received the data.

Ideally you would change findWarehouseKeepers to return a promise, but here is an example with minimal changes to your code:

handle(handlerInput) {
  return new Promise(resolve => {
    findWarehouseKeepers(warehouseKeeper => {
      const speakOutput = "Die Lagerhüter sind die Produkte mit den Ids" + warehouseKeeper;
      resolve(
        handlerInput.responseBuilder
          .speak(speakOutput)
          .getResponse()
      );
    });
  });
}

Of course you would also want to think about what to do if the request fails, i.e. you want to reject the promise.


If you change findWarehouseKeepers to return a promise then you could probably write declare handle as async (I don't know in which environment this code runs) and write the code in a way that looks synchronous:

async handle(handlerInput) {
  const warehouseKeeper = await findWarehouseKeepers();
  return handlerInput.responseBuilder
    .speak("Die Lagerhüter sind die Produkte mit den Ids" + warehouseKeeper)
    .getResponse()
}

Upvotes: 2

Related Questions