提问者:小点点

UnhandledPromiserEjectionWarning:NodeJs中_.map中未处理的promise拒绝


当我运行下面的代码块时,我总是得到错误-UnhandledPromiseRejectionWarning:UnhandledPromiseRejection。 此错误可能是由于不带catch块的异步函数内部引发的,或者是由于拒绝了未用。catch()处理的承诺。 要在未处理的承诺拒绝时终止节点进程,请使用CLI标志--unhandled-rejections=strict(请参阅https://nodejs.org/api/CLI.html#CLI_unhandled_rejections_mode)。 (拒绝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 
};

我很肯定这是因为search_and_add函数中的map语句,但我不知道如何去掉它,提供相同的功能并使try catch块工作? 有人能帮忙吗?


共2个答案

匿名用户

search_and_add中的_.map(…)调用的回调所创建的承诺没有执行任何操作。 它们只是被忽略,不被等待,当被拒绝时会引起警告。 想必您的意思是使用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);
    });
}

匿名用户

  • 您正在使用map函数,因为您需要用Promise.AllSettled函数换行。

Promise.allSettled在node JS12版本及以上版本中可用。 如果您使用的节点少于12,则需要使用promise.all

AllSettled():promise.AllSettled()方法返回一个承诺,该承诺在所有给定的承诺实现或拒绝后进行解析,并带有一个对象数组,每个对象描述每个承诺的结果。

当您有多个异步任务,而这些任务彼此不依赖于才能成功完成时,或者您总是想知道每个承诺的结果时,通常会使用它。

All():Promise.all()方法接受一个iterable of promises作为输入,并返回一个Promise作为输出。 当所有输入的承诺都已解决并且非承诺已返回时,或者如果输入iterable不包含承诺时,返回的承诺将会解决。 当任何输入承诺拒绝或非承诺抛出错误时,它立即拒绝,并将以第一个拒绝消息/错误拒绝。

当有多个异步任务相互依赖才能成功完成时,它通常会使用,因为它不会等待,并且会在任何输入承诺拒绝时立即拒绝。

请参阅:

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

对于异步等待中的错误处理:

Async Await本质上是承诺的语法糖,如果Await语句出错,它将返回一个被拒绝的承诺,而不是在每个可以编写helper函数的地方添加try-catch,该函数包装我们的快速路由,以处理所有被拒绝的路由承诺。

    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包异步中间件。