0

I did a couple of projects with node.js and I'm aware of the async behaviour and that one should usually use callback functions, etc. But one thing that bothers me ist the following.

I'm developing an Alexa skill and I have a function that handles the User intent:

'MyFunction': function() {
  var toSay = ""; // Holds info what Alexa says
  
  // Lot of checks and calculations what needs to be said by Alexa (nothing special)
  if(xyz) {
    toSay = "XYZ";
  }else if(abc) {
    toSay = "ABC";
  }else{
    toSay = "Something";
  }
  
  // Here is the "tricky" party
  if(someSpecialEvent) {
    toSay += " "+askDatabaseForInput(); // Add some information from database to string
  }
    
  this.emit(':ask', toSay, this.t('REPROMT_SPEECH')); // Gives the Info to Alexa (code execution stops here)
}

As mentioned in the code, there is some code which is usually used to find out what the output to Alexa should be. Only on rare events, "someSpecialEvent", I need to query the database and add information to the String "toSay".

Querying the DB would look something like:

function askDatabaseForInput() { // The function to query the DB
  var params = {
    TableName: "MyTable",
    OtherValues: "..."
  };
  
  // Do the Query
  docClient.query(params, function(err, data) {
    // Of course here are some checks if everything worked, etc.
    var item = data.Items[0]; 
    return item; // Item SHOULD be returned
  });
  
  return infoFromDocClient; // Which is, of course not possible
}

Now I know, that in the first function "'MyFunction'" I could just pass the variable "toSay" down to the DB Function and then to the DB Query and if everything is fine, I would do the "this.emit()" in the DB Query function. But for me, this looks very dirty and not much reusable.

So is there a way I can use "askDatabaseForInput()" to return DB information and just add it to a String? This means making the asynchronous call synchronous.

Making a synchronous call wouldn't affect the user experience, as the code isn't doing anything else anyway and it just creates the String and is (maybe) waiting for DB input.

Thanks for any help.

Rob
  • 14,746
  • 28
  • 47
  • 65
Nightflash
  • 118
  • 4
  • 1
    You can make `askDatabaseForInput` take a callback too. Just a regular argument. – Ry- Jan 28 '18 at 22:03
  • I'm somehow stuck. How would that help in my situation? – Nightflash Jan 28 '18 at 22:08
  • Seems pretty much like a dup of:https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call/14220323#14220323. Can't take an async value and return is synchronously. Javascript simply can't do that and your DB calls are only asynchronous. So, the result from the DB must be used asynchronously - period. – jfriend00 Jan 29 '18 at 03:53

1 Answers1

0

So you could do 2 things:

Like the person who commented says you could use a callback:

function askDatabaseForInput(callback) {
  var params = {
    TableName: "MyTable",
    OtherValues: "..."
  };

  docClient.query(params, function(err, data) {
    if (err) {
      callback(err, null)
    } else {
      var item = data.Items[0]; 
      callback(null, item);
    }
  });
}

or you could use promises:

function askDatabaseForInput() {
  var params = {
    TableName: "MyTable",
    OtherValues: "..."
  };
  return new Promise(function (resolve, reject) {
    docClient.query(params, function(err, data) {
      if (err) {
        reject(err)
      } else {
        var item = data.Items[0]; 
        resolve(item);
      }
    });
  });
}

you can then either put a function in where you call askDatabaseForInput or do askDatabaseForInput.then(....).

In the function or the .then you would add what you retrieved from the database to the variable toSay

hope this helps

Jack
  • 67
  • 8
  • Oh yes. I really was stuck yesterday. Thanks Jack and Ryan. Of course using a callback helps here. It is not as "good looking" as if "askDatabaseForInput()" would just return the info, but by using "askDatabaseForInput(function(err, data) { xxx});" it at least keeps the logic where it belongs. – Nightflash Jan 29 '18 at 08:13