UnhandledPromiseRejectionWarning: Unhandled promise rejection in _.map in NodeJs

10,129

Solution 1

You're not doing anything with the promises created by the callback to the _.map(…) call in search_and_add. They just get ignored, are not awaited, and will cause the warning when getting rejected. Presumably you meant to use Promise.all there?

function search_and_add(req, res, spotifyAPI, to_filter, playlist_id) {
    return Promise.all(to_filter.map(async (tag) => {
//         ^^^^^^^^^^^^
        const song_details = await spotifyAPI.searchTracks(tag.name, { limit: 1 });
        //const song_uri = song_details['body']['tracks']['items'][0]['id'];
        console.log(song_details);
    });
}

Solution 2

  • You are using map function since you need to wrap with Promise.allSettled function.

Promise.allSettled is available in node js 12 version and above. if you are using less than node 12 then you need to use Promise.all

Promise.allSettled(): The Promise.allSettled() method returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.

It is typically used when you have multiple asynchronous tasks that are not dependent on one another to complete successfully, or you'd always like to know the result of each promise.

Promise.all(): The Promise.all() method takes an iterable of promises as an input, and returns a single Promise as an output. This returned promise will resolve when all of the input's promises have resolved and non-promises have returned, or if the input iterable contains no promises. It rejects immediately upon any of the input promises rejecting or non-promises throwing an error, and will reject with this first rejection message / error.

It is typically used when there are multiple asynchronous tasks that are dependent on one another to complete successfully, as it does not wait and will reject immediately upon any of the input promises rejecting.

refer this:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

https://sung.codes/blog/2019/05/18/promise-race-vs-promise-any-and-promise-all-vs-promise-allsettled/

        const search_and_add = (req, res, spotifyAPI, to_filter, playlist_id) {
          return Promise.allSettled(to_filter.map(async (tag) => {
                const song_details = await spotifyAPI.searchTracks(tag.name, { limit: 1 });
                //const song_uri = song_details['body']['tracks']['items'][0]['id'];
                console.log(song_details);
               return song_details;
            }).catch(function(err){
               console.log(err);
              
              return err;
             });
        }

For error handling in async await:

Async Await is essentially syntactic sugar for promises, and if an await statement errors it will return a rejected promise, Instead of adding try -catch every where we can write a helper function that wraps our express routes to handle all rejected promises of route.

    const asyncMiddleware = fn =>
      (req, res, next) => {
        Promise.resolve(fn(req, res, next))
          .catch(next);
      };

then wrap your route function like this

    router.get('/users/:id', asyncMiddleware(async (req, res, next) => {
        /* 
          if there is an error thrown in getUserFromDb, asyncMiddleware
          will pass it to next() and express will handle the error;
        */
        const user = await getUserFromDb({ id: req.params.id })
        res.json(user);
    }));
    

Note: You can also use npm package async-middleware for this.

Share:
10,129

Related videos on Youtube

Uddhav Bhagat
Author by

Uddhav Bhagat

Updated on June 04, 2022

Comments

  • Uddhav Bhagat
    Uddhav Bhagat over 1 year

    I always get the error when I run the code block below - UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)

    
    module.exports = (app, spotifyAPI) => {
    
        app.get('/api/search', requireLogin, async (req, res) => {
    
            const URI_BASE = keys.ComputerVisionEndpoint + 'vision/v3.0/analyze';
            const imageUrl = "https://upload.wikimedia.org/wikipedia/commons/3/3c/Shaki_waterfall.jpg"; // will be sent as req body
            var results;
    
            // making API call to microsoft cognitive services API 
            try {
                results = await axios({
                    method: 'post',
                    url: URI_BASE,
                    headers: {
                        'Content-Type': 'application/json',
                        'Ocp-Apim-Subscription-Key' : keys.ComputerVision
                    }, 
                    params: {
                        'visualFeatures': 'Tags',
                        'details': '',
                        'language': 'en'
                    },
                    data: {
                    "url": imageUrl,
                    }
                });
            } catch (err) {
                return res.status(400).send(err);
            }
    
            // remove the common ones - indoor, outdoor, ground, wall, person, woman, man, ceiling, floor
            const to_filter = results['data']['tags'];
            _.remove(to_filter, (item) => {
                return (item.name === 'indoor' || item.name === 'outdoor' || item.name === 'ground' || item.name === 'wall'
                    || item.name === 'person' || item.name === 'woman' || item.name === 'man' || item.name === 'ceiling'
                    || item.name === 'floor'
                );
            });
    
    
            // searching for relevant songs and adding them to the playlist
            var id;
            try {
                id = await search_and_add(req, res, spotifyAPI, to_filter, playlist_id);
            } catch (err) {
                if (err['statusCode'] === 401) {
                    req.logout();
                    return res.redirect('/');
                }
                else {
                    return res.status(400).send(err);
                }
            }
    
        });
    }
    
    search_and_add = async (req, res, spotifyAPI, to_filter, playlist_id) => {
        _.map(to_filter, async (tag) => {
            try {
                const song_details = await spotifyAPI.searchTracks(tag.name, { limit: 1 });
                //const song_uri = song_details['body']['tracks']['items'][0]['id'];
                console.log(song_details);
            } catch (err) {
                throw err;
            }
        });
         return;
        // figure out where to re direct user 
    };
    

    I'm pretty sure it is because of the map statement in the search_and_add function, but I do not know how to get rid of it and provide the same functionality to make the try-catch block work? Could someone help?

    • Bergi
      Bergi over 3 years
      You're not doing anything with the promises created by the callback to the _.map(…) call in search_and_add. Presumably you meant to use Promise.all there?
  • Uddhav Bhagat
    Uddhav Bhagat over 3 years
    Hi, sorry I'm new to this. Could you clarify this and explain how this works?
  • Bergi
    Bergi over 3 years
    @UddhavBhagat Do you understand how Promise.all works?
  • Uddhav Bhagat
    Uddhav Bhagat over 3 years
    I'm afraid not really. Also, I do not know what exactly you mean by 'You're not doing anything with the promises created by the callback to the _.map(…) call in search_and_add'?
  • Uddhav Bhagat
    Uddhav Bhagat over 3 years
    How would I check for error handling in try catch block when I use Promise.allSettled()? Would it have to be for all individual elements?
  • Vijay Palaskar
    Vijay Palaskar over 3 years
    }).catch(function(err){ console.log(err); return err; }); you can add .like this to catch the errors
  • Uddhav Bhagat
    Uddhav Bhagat over 3 years
    So, in the part where I'm calling search_and_add function, what would be returned there? If I return err, would it be returned to the main function from where I call search_and-add?
  • Vijay Palaskar
    Vijay Palaskar over 3 years
    you need to return song_details.& for error return error or empty pbject..so you will get all in array.I have edited the answer check now