javascript - UnhandledPromiseRejectionWarning:NodeJs 中 _.map 中未处理的承诺拒绝
问题描述
当我运行下面的代码块时,我总是收到错误 - UnhandledPromiseRejectionWarning:未处理的承诺拒绝。此错误源于在没有 catch 块的情况下抛出异步函数内部或拒绝未使用 .catch() 处理的承诺。要在未处理的 Promise 拒绝时终止节点进程,请使用 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 函数中的 map 语句,但我不知道如何摆脱它并提供相同的功能来使 try-catch 块工作?有人可以帮忙吗?
解决方案
- 您正在使用 map 函数,因为您需要使用 Promise.allSettled 函数进行包装。
Promise.allSettled 在 node js 12 及以上版本中可用。如果您使用的节点数少于 12,那么您需要使用 Promise.all
Promise.allSettled():Promise.allSettled() 方法返回一个在所有给定的 Promise 都已实现或拒绝后解析的 Promise,并带有一组对象,每个对象都描述了每个 Promise 的结果。
它通常用于当您有多个不相互依赖的异步任务才能成功完成,或者您总是想知道每个承诺的结果。
Promise.all():Promise.all() 方法将一个可迭代的 Promise 作为输入,并返回一个 Promise 作为输出。当所有输入的承诺都已解决且非承诺已返回,或者输入可迭代不包含任何承诺时,此返回的承诺将解决。它会在任何输入的 promise 被拒绝或 non-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
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 本质上是 Promise 的语法糖,如果 await 语句出错,它将返回一个被拒绝的 Promise,而不是在每个地方添加 try -catch,我们可以编写一个帮助函数来包装我们的 express 路由来处理所有被拒绝的路由 Promise。
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 包async-middleware。
推荐阅读
- powerbi - 如何从 Power Query M(Power BI)的另一个表中的特定 clumn 中获取最小值?
- arrays - 在块范围内被覆盖的未初始化数组的值
- javascript - 使用 Mongoose 批量处理 MongoDB 集合
- clarifai - 尝试创建新模型时出错
- c# - 如何访问 ascx 控件的代码隐藏对象中的公共变量?(内联表达式)
- php - 更改状态 php ajax 和脚本和值输入
- mysql - MYSQL 创建一个透视值到列分组依据
- php - PHP中Curl API调用中的标题参数问题
- delphi - 如何将单(')或双(“)引号添加到pascal中的字符串?
- liferay - Liferay 7 Login Post Event 可以在portal-ext.properties 中设置吗?