简体   繁体   中英

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

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.

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.

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));
    // ...
  }
});

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM