UnhandledPromiseRejectionWarning: отклонение необработанного обещания в _.map в NodeJs - PullRequest
1 голос
/ 13 июля 2020

Я всегда получаю сообщение об ошибке при запуске блока кода ниже - UnhandledPromiseRejectionWarning: необработанное отклонение обещания. Эта ошибка возникла либо из-за выброса внутри функции asyn c без блока catch, либо из-за отклонения обещания, которое не было обработано с помощью .catch (). Чтобы завершить процесс узла при отклонении необработанного обещания, используйте флаг CLI --unhandled-rejections=strict (см. https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (идентификатор отклонения: 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 
};

Я почти уверен, что это из-за оператора карты в функции search_and_add, но я не знаю, как избавиться от него и обеспечить ту же функциональность и сделать блокировка try catch работает? Может кто-нибудь помочь?

Ответы [ 2 ]

1 голос
/ 13 июля 2020
  • Вы используете функцию карты, поскольку вам нужно обернуть ее функцией Promise.allSettled.

Promise.allSettled доступен в версии node js 12 и выше. если вы используете узел меньше 12, вам нужно использовать Promise.all

Promise.allSettled () : метод Promise.allSettled () возвращает обещание, которое разрешается после всех данные обещания либо выполнены, либо отклонены, с массивом объектов, каждый из которых описывает результат каждого обещания.

Обычно он используется, когда у вас есть несколько асинхронных задач, которые не зависят друг от друга для успешного выполнения, или вы всегда хотели бы знать результат каждого обещания.

Promise.all () : метод Promise.all () принимает в качестве входных данных итерацию обещаний и возвращает single Promise как выход. Это возвращенное обещание разрешится, когда все входные обещания разрешены и не-обещания вернулись, или если итерируемый входной объект не содержит обещаний. Он немедленно отклоняет любое из входных обещаний, отклоняющих или не-обещаний, вызывающих ошибку, и будет отклонять с этим первым сообщением / ошибкой об отклонении.

Обычно используется, когда есть несколько асинхронных задач, которые зависят от одной другой для успешного завершения, так как он не ждет и немедленно отклоняет любое из входных обещаний.

см. это:

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

Для обработки ошибок в asyn c await:

Asyn c Await, по сути, синтаксис c сахар для обещаний, и если оператор await ошибается, он вернет отклоненное обещание. Вместо добавления try -catch каждый раз, когда мы можем написать вспомогательную функцию, которая обертывает наши express маршруты для обработки всех отклоненных обещаний маршрута.

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

затем оберните свою функцию маршрута следующим образом

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

Примечание: вы также можете использовать npm package asyn c -среднее ПО для этого.

1 голос
/ 13 июля 2020

Вы ничего не делаете с обещаниями, созданными обратным вызовом для вызова _.map(…) в search_and_add. Их просто игнорируют, их не ждут, и они будут вызывать предупреждение при отклонении. Предположительно вы хотели использовать там Promise.all?

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);
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...