How to use callback in JS (node) to wait for Async function to finish before proceeding?

Related searches

I have an function called translateCommand(command) that uses a Translate package from npm to translate some text into a different language. The problem is the translate function provided by that package is asynchronous and it tends to exit the translateCommand function before the translate function is finished, resulting in the return of garbage data.

I identified it finishing too fast as the issue and made translateCommand(command) an async function, so that I could use await in front of the imported translate() function, which solved that issue, but now I've simply delayed the issue a step further back because the function that calls translateCommand(command) is experiencing the exact same issue and I feel like I've made no headway if I'm just going to have to keep repeating this chain upward.

Fact of the matter is, I don't really understand Promises and how Async functions behave in general in relation to them. I realize this is a premise that makes Node.js great, but trying to learn about it has been fairly ineffective. Trying to solve this problem hasn't really bore fruit as everyone just says to use callback without explaining what exactly a callback is. It doesn't help that the examples were usually surrounded with unfamiliar code, so I figured getting help in the context of my code would tackle two birds with one stone.

This whole process is my introductory attempt to make a silly Discord Bot where I've implemented a bunch of silly features. I've ran into the Async wall many times, but usually found a Synchronous alternative to proceed forward. This time I did not, and I've tried to emulate callbacks described in other Stack Overflow posts, but due to a lack of understanding, was unable to integrate them correctly (I can only assume).

Top-level imported function that now has the Async issue.

client.on("message", (message) => {

    // ...
    let command = (message.content).substr(1);

    // ...

    // Handles translate command
    else if (command.startsWith("translate"))
        message.channel.send(translateCommand(command));

    // ...
    }
});

Function that was made async so it could await:

// Form !translate [string]
async function translateCommand(command) {
    let message = "";
    let str = command.substr(10);

    await translate(str, { to: 'ja', engine: 'yandex', key: '<my key>' }).then(function(result) {
        message = result;
        return "";
    });
    return message;
}

I'm aware this question has been asked to death, but I feel that without context I understand (as I'm still new to both JS and Node), I can only proceed by beating my head against a wall until something works without me understanding why.

Because translate returns a promise you don't need to make translateCommand async. Simply return translate from the function...

function translateCommand(command) {
  let str = command.substr(10);
  return translate(str, { to: 'ja', engine: 'yandex', key: '<my key>' });
}

...and await the promise to resolve. You need to add async to the event handler callback for await to work.

client.on("message", async (message) => {

  let command = (message.content).substr(1);

  //...

  else if (command.startsWith("translate"))
    message.channel.send(await translateCommand(command));
    // ...
  }
});

How to wait for a promise to finish before returning the variable of a , Use of setTimeout() function: In order to wait for a promise to finish before returning the variable, the function can be set with setTimeout(), so that the function waits for a few milliseconds. Use of async or await() function: This method can be used if the exact time required in setTimeout() cannot be specified. Asynchronous requests will wait for a timer to finish or a request to respond while the rest of the code continues to execute. Then when the time is right a callback will spring these asynchronous requests into action. This is an example of an asynchronous code:

You can change your top-level function to be async as well. Change the beginning to async (message) => { and use message.channel.send(await translateCommand(command)). Alternatively, you could opt to use promises and not make the function async, and instead use translateCommand(command).then(msg => message.channel.send(msg)), however it could mess up the flow later in the code.

JavaScript — from callbacks to async/await, Before the code executes, var and function declarations are “hoisted” to the top of Asynchronous requests will wait for a timer to finish or a request to first as parameter is a common practice especially when using Node.js. If GoDoSomeStuff () contains async calls then you would need to put your console.log statements in the completion call back of those calls (or use a Promise and Promise.all to wait on multiple async events). The code is important here. I will do a screen print of the output.

Using promises, you could do the following:

translateCommand function:

var translateCommand = (command) => new Promise((resolve,reject) =>  {
    translate(command.substr(10), { to: 'ja', engine: 'yandex', key: '<my key>' })
        .then(resolve)
        .catch(reject)
    });

then client.on:

client.on("message", (message) => {

    // ...
    let command = (message.content).substr(1);

    // ...

    // Handles translate command
    else if (command.startsWith("translate"))
        translateCommand(command)
            .then(translationResult => {
               message.channel.send(translationResult)
            })
    // ...
    }
});

If you have troubles with the syntax, here are the hints: hint #1 hint #2 + One remark - don't be afraid and take your time to read + implement the above examples and modify them afterwards to cause errors (you will know how and when they do or do not work - painful but rewarding ;) )

JavaScript: Promises and Why Async/Await Wins the Battle, Note: I'm going to be using arrow functions in this blog post. /error-handling-in- node-javascript-suck-unless-you-know-this-2018-aa0a14cfdd9d This is my attempt to explain how to use asynchronous code in Javascript at a very high level. They won't wait for the last function to finish before they start. The async keyword is used to create an asynchronous function that returns a promise that is either rejected or resolved. The promise is rejected when there is an uncaught exception thrown from that function or it is resolved otherwise. The await keyword is used inside an async function to pause its execution and wait for the promise.

Callbacks, Promises and Async/Await, When it comes to JavaScript we rely heavily on callback functions to before you might have already spotted why we're not going to get a quote But because the request function executes asynchronously, JavaScript does not wait around for it to finish. Let's take the Twilio Node.js library for example. This let’s JavaScript know that we are using async/await syntax, and is necessary if you want to use Await. This means you can’t use Await at the global level; it always needs a wrapper function.

Async/Await: The Hero JavaScript Deserved, Save the file with name functionCallFlowWithAsync.html and open it in any browser (Chrome, Firefox, or IE).It should show the output as: Here, we explicitly introduced a time delay of 1500 ms before returning the response from the function first(), and the screenshot depicts that JavaScript didn’t wait for the first() function to finish its execution, and it continued with the execution of

Async functions return a Promise by default, so you can rewrite any callback based function to use Promises, then await their resolution. You can use the util.promisify function in Node.js to turn callback-based functions to return a Promise-based ones.

Comments
  • async (message) => { and message.channel.send(await translateCommand(command));
  • So I can scrap the .then(function(result) { message = result; return ""; }) part entirely? Also as a followup, how is it that the result parameter was capturing the output of translate anyways? Sorry and thank you so much.
  • Instead of then you could have used const message = await translate(...), and then you would return message. But you can miss that step out and simply return the promise instead. In your code result is just the data (as argument) in the resolve function. It could have been named anything. Anyway, give it a test and see if it works for you.
  • PS. You can see the difference between then and await in this jsfiddle.
  • client.on("message", async (message) => { // ... }}); Assuming this is the correct implied structure, suggested by the first method (correct me if I'm wrong). Are there any consequences to other synchronous functions in this top-level function that will be using message? Also what do you mean by the Promise route potentially messing up the flow later in the code? Sorry and thank you.
  • Thank you for providing another approach! It really helps to see all the ways to solve this problem, also embarrassingly validates my confusion on the topic as I think I tried pieces of all of these solutions mixed together. Following your hints, I just realized why I was getting so confused with arrow functions (they're basically Lambda Functions right?), it's cause if they have a single parameter, you can remove the parenthesis surrounding the parameter, which confused me eternally.
  • It has been a very long time since I touched C#, but yes, I think the fat arrow functions (since they have that funny name in javascript) can be perceived as lambda expressions (at least in this case). I'm happy I could help. Also - yes, when they take single parameter, the parentheses can be omitted (one little downside is that it introduces code readability 'difficulties' [non unified syntax] when declaring multiple functions with different number of parameters).
  • The key difference between normal functions and arrow functions is that arrow functions don't have their own this or arguments. They inherit their this from the outer lexical environment which saves on assigning this to self, or binding.
  • @Andy: no one mentioned 'normal' functions, but lambda and arrow ones
  • And I explained the difference between them. What's the problem?