0

I have a search form that returns a result after going through 3 Async APIs (Spotify, Twitter and Google Sentiment Analysis).

The issue: The result is rendered on the page too late whereby I am getting undefined values (while in console log the values are returned correctly after a delay)

Question: How do I wait for the values to be returned before i use res.render() to display on page?

Code:

router.post('/', (req, res) => { 
    const sentiment = sentimentAnalyze(req.body);
     res.render('home', { name: sentiment.artistName, score:sentiment.score, mag:sentiment.mag});


});
async function sentimentAnalyze(searchValue){
    try {
        const artist = await searchedArtist(searchValue);
        const tweetsDoc= await getTwitterResults(artist);
        const sentiment = await googleAnalyze(tweetsDoc);
        return sentiment;
    } catch(err) {
        console.log('Error::: ', err);
    } 
}
function searchedArtist(searchValue) {
    return new Promise((resolve, reject) => {
        if(searchValue != null) {   
            let name = searchValue.name;
            let twitterResults;
            // Get artist
            getArtist(name, "artist").then((response) => {
                data = {
                "id": response.artists.items[0].id,
                "name":  response.artists.items[0].name
                }
                // resolve and return the aritst object
                resolve(data);
            });
        }
    });
}
function getTwitterResults(data) {
    return new Promise((resolve, reject) => {
        client.get('search/tweets', {q: data.name}, function(error, tweets, response) {
            let resultObject = search("", tweets.statuses);
            //  console.log(resultObject); 
            //  The text to analyze
            const document = {
                content: resultObject,
                type: 'PLAIN_TEXT',
                artistName: data.name
            };
            resolve(document);
        });
    });
}
// Detects the sentiment of the text
function googleAnalyze(document) {
    return new Promise((resolve, reject) => {
      // Detects the sentiment of the text
      googleClient
        .analyzeSentiment({document: document})
        .then(results => {
          const sentiment = results[0].documentSentiment;

          console.log(`Sentiment score of ${data.name}: ${sentiment.score}`);
          console.log(`Sentiment magnitude: ${sentiment.magnitude}`);     
          // return sentiment reponse 
          resolve(sentiment);
        })
        .catch(err => {
          console.error('GOOGLE API ERROR:', err);
        });
    });
 }

Please help, new to Async Js!

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
Shaz
  • 1,443
  • 1
  • 27
  • 67
  • Change `router.post` callback to `async` and then `await sentimentAnalyze(...` – CertainPerformance Sep 15 '18 at 02:49
  • @CertainPerformance Thanks for reply. How do I change router.post to async callback... I don't understand, pleasee explain – Shaz Sep 15 '18 at 02:51
  • The same way you made your `sentimentAnalyze` `async`. Use the `async` keyword – CertainPerformance Sep 15 '18 at 02:52
  • @CertainPerformance If I add synce to router,post i.e. async router.post('/', (req, res) => { that gives me error? I don't understand how router can have async? can u give me an example please? sorry new to javascript – Shaz Sep 15 '18 at 02:56
  • @CertainPerformance like this: router.post('/', (req, res, async) => { const sentiment = await sentimentAnalyze(req.body); res.render('home', { name: sentiment.artistName, score:sentiment.score, mag:sentiment.mag}); }); – Shaz Sep 15 '18 at 03:02
  • Please read the [documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) on how to use `async` functions. You already implemented it once in your code already, just do the same thing for the `router.post` callback – CertainPerformance Sep 15 '18 at 03:03
  • @CertainPerformance Yes, but I'm stuck at the router.post level, where I confused as to how it would be done. I've tried this: router.post('/', (req, res) => { sentiment = await search(); res.render('home', { name: sentiment.artistName, score:sentiment.score, mag:sentiment.mag}); }); async function search() { return new Promise((resolve, reject) => { const sentiment = sentimentAnalyze(req.body); resolve(sentiment); }); } – Shaz Sep 15 '18 at 03:16
  • 1
    `router.post('/', async (req, res) => { ... })`. Now you can use `await` inside the function. – Roamer-1888 Sep 15 '18 at 06:39
  • @Roamer-1888 My bad, it works! Thank you. If you post it as an answer I'll give you the tick – Shaz Sep 15 '18 at 07:03
  • Had zero idea you could add async function into post like this – Shaz Sep 15 '18 at 07:04
  • The second argument of `router.post()` is an anonymous function. Any javascript function, including anonymous ones, can be designated `async`. – Roamer-1888 Sep 15 '18 at 07:42
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) in `searchedArtist` and `googleAnalyze`! – Bergi Sep 15 '18 at 08:49

0 Answers0