【问题标题】:UnhandledPromiseRejectionWarning even though code has try/catch within async/awaitUnhandledPromiseRejectionWarning 即使代码在 async/await 中有 try/catch
【发布时间】:2019-07-03 04:24:41
【问题描述】:

我意识到这似乎与其他问题重复,但在发布此问题之前,我已经查看了我可以找到的每个建议的 SO 问题,并且我正在寻求有关此特定情况的帮助,因为其他答案都没有奏效对我来说。

我有一个 Node/Express 应用程序,它正在初始化一个 MongoDB 连接以供 REST API 使用。第一步是连接到 MongoDB 实例。如果初始连接失败,它将按预期抛出错误。我正在使用带有 try/catch 块的 async/await 来处理它。我看过的所有地方都说这应该足以捕获这些 async/await 承诺拒绝,但是无论我在哪里输入 .catch() 或 try/catch 我的代码,我都会收到有关 UnhandledPromiseRejection 的错误(如其他所以帖子)。

例如,在此链接中,我的内容与错误处理部分中描述的内容几乎相同,但问题仍然存在。

https://javascript.info/async-await

这是错误(我知道是什么导致了错误本身 - 我现在停止了 MongoDB 服务 - 但我正在尝试修复未处理的承诺拒绝错误):

(node:15633) 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(). (rejection id: 1) (node:15633) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. (node:13802) UnhandledPromiseRejectionWarning: MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017] at Pool.<anonymous> (/home/allen/scripts/lysi/eosMain/node_modules/mongodb-core/lib/topologies/server.js:562:11) at Pool.emit (events.js:189:13) at Connection.<anonymous> (/home/allen/scripts/lysi/eosMain/node_modules/mongodb-core/lib/connection/pool.js:316:12) at Object.onceWrapper (events.js:277:13) at Connection.emit (events.js:189:13) at Socket.<anonymous> (/home/allen/scripts/lysi/eosMain/node_modules/mongodb-core/lib/connection/connection.js:245:50) at Object.onceWrapper (events.js:277:13) at Socket.emit (events.js:189:13) at emitErrorNT (internal/streams/destroy.js:82:8) at emitErrorAndCloseNT (internal/streams/destroy.js:50:3) at process._tickCallback (internal/process/next_tick.js:63:19)

这是我的代码:

exports.mongoConnect = async (dbName, archiveDbName, userName, password) => {

    // Auth params
    const user = encodeURIComponent(userName);
    const pass = encodeURIComponent(password);
    const authMechanism = 'DEFAULT';

    // Connection URL
    const url = `mongodb://${user}:${pass}@localhost:27017?authMechanism=${authMechanism}&authSource=admin`;
    let client;

    try {
        // Use connect method to connect to the Server
        client = await MongoClient.connect(url, { useNewUrlParser: true, poolSize: 10, autoReconnect: true, reconnectTries: 6, reconnectInterval: 10000 }).catch((e) => { console.error(e) });

        db = client.db(dbName);
        archiveDb = client.db(archiveDbName);

        console.log(`Succesfully connected to the MongoDb instance at URL: mongodb://localhost:27017/ with username: "` + client.s.options.user + `"`);
        console.log(`Succesfully created a MongoDb database instance for database: "` + db.databaseName + `" at URL: mongodb://localhost:27017/`);
        console.log(`Succesfully created a MongoDb database instance for database: "` + archiveDb.databaseName + `" at URL: mongodb://localhost:27017/`);
    } catch (err) {
        console.log(`Error connecting to the MongoDb database at URL: mongodb://localhost:27017/` + dbName);
    }
}

像这样从 app.js 调用:

mongoUtil.mongoConnect('myDb', 'myArchiveDb', 'myUser', 'myPassword');

我什至尝试将该行放在 try/catch 块中,或者在其末尾添加 promise 样式的 .catch(),没有任何变化。

我似乎无法弄清楚为什么它仍然抱怨没有处理承诺拒绝。

编辑:

这是整个 app.js 文件:

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var cors = require('cors');
var app = express();

const MongoClient = require('mongodb').MongoClient;
// This is where the mongo connection happens
var mongoUtil = require( './services/mongoUtil' );
var bluebird = require('bluebird');

const jwt = require('./helpers/jwt');

var api = require('./routes/api.route')

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(cors());
app.use(logger('dev'));
app.use(express.json()); 
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/api', api);

// use JWT auth to secure the api
app.use(jwt());

app.use('/users', require('./users/users.controller'));

MongoClient.Promise = bluebird

mongoUtil.mongoConnect('myDb', 'myArchiveDb', 'username', 'password');

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
  next();
});

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;`

【问题讨论】:

  • 你能确定你的 MongoDB 服务器正在运行吗?
  • 它当前没有运行,但这并不是我要问的问题。这始于我不小心尝试在没有运行 MongoDB 的情况下启动我的应用程序。它抛出了这个错误,所以我想调查是什么原因造成的,因为我似乎没有正确处理它无法连接到 MongoDB 时发生的错误。实际问题是通过启动 MongoDB 解决的,但这并不能解决承诺拒绝没有得到正确处理的事实。
  • 啊好吧!得到你。为什么不使用Promise 符号? MongoClient.connect(...).then(() =&gt; { // all good }).catch((error) =&gt; { // error here })
  • 他还说他已经尝试过了,一切都在问题中...... @NellaGnute:在您的代码中看不到任何明显错误,将投票并等待更有知识的人回答我很好奇!
  • MongoClient.connect 会返回一个 Promise 吗?

标签: node.js error-handling promise async-await


【解决方案1】:

我测试了您的代码,它运行良好,您可以在下面的屏幕截图中看到。我认为问题在于调用 mongoConnect()

【讨论】:

  • 可能是版本问题?当 MongoDB 正在运行时,我的工作正常,但是当它没有运行并且失败时,我得到一个 unhandledPromiseRejection 错误,而你没有出于某种原因。我在节点 10.15.1 和 NPM 6.7.0 上使用“npm start”运行它
  • 我在节点 8.9.1,我现在正在尝试 10.15.1,会告诉你
  • 它也适用于节点 10.15.1。这让我认为这是上游的问题,即调用你的 mongoConnect 函数的问题
  • 这太糟糕了——有什么好的解决方法的建议吗?我想说我可以在这里粘贴整个 app.js 代码,但这似乎不太礼貌,而且可能会超出字符数限制。或者可能是 Mongo 版本?我目前使用的是 4.0.5。
  • 该警告从 8.2.1 开始。我认为这两个版本都应该返回它。另外,也许您可​​以使用 www.repl.it 进行 Node 在线沙箱调试
【解决方案2】:

您正在以同步方式从app.js 调用connect,因此您的async/await 方法将不起作用。您可以使用sleep 函数对其进行测试:

let sleep = () => {
  return new Promise(function(resolve, reject) {
    setTimeout(function(){
      console.log('Finished sleeping');
      resolve();
    }, 2000)
  })
}

exports.mongoConnect = async (dbName, archiveDbName, userName, password) => {
  await sleep() // sleep two seconds
  // rest of your mongoConnect code
})

然后在连接后添加登录app.js

mongoUtil.mongoConnect('myDb', 'myArchiveDb', 'username', 'password');
console.log('Finished connection');

您将在控制台中获得以下输出:

Finished connection // You can see the code doesnt wait to mongo to connect
[After 2 seconds]
Finished sleeping // After this sleep log it will start connecting...

要解决这个问题,您需要以异步方式执行 app.js

建议不要使用顶级异步函数,但我希望您看到错误

(async () => {
    // rest of your app.js
    await mongoUtil.mongoConnect('myDb', 'myArchiveDb', 'username', 'password');
    console.log('Finished connection attempt');
    // rest of your app.js
})()

然后我在控制台遇到的错误是(没有警告!):

{ MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017]
    at Pool.<anonymous> (/node_modules/mongodb-core/lib/topologies/server.js:564:11)
    at Pool.emit (events.js:182:13)
    at Connection.<anonymous> (/node_modules/mongodb-core/lib/connection/pool.js:317:12)
    at Object.onceWrapper (events.js:273:13)
    at Connection.emit (events.js:182:13)
    at Socket.<anonymous> (/node_modules/mongodb-core/lib/connection/connection.js:246:50)
    at Object.onceWrapper (events.js:273:13)
    at Socket.emit (events.js:182:13)
    at emitErrorNT (internal/streams/destroy.js:82:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
    at process._tickCallback (internal/process/next_tick.js:63:19)
  name: 'MongoNetworkError',
  errorLabels: [ 'TransientTransactionError' ],
  [Symbol(mongoErrorContextSymbol)]: {} }
Error connecting to the MongoDb database at URL: mongodb://localhost:27017/myDb
Finished connection attempt

【讨论】:

  • 经过大量研究,现在我意识到以同步方式调用 mongoUtil.mongoConnect 不会对我发出任何警告......
猜你喜欢
  • 2019-03-14
  • 2021-08-28
  • 1970-01-01
  • 2018-06-21
  • 2017-11-23
  • 2019-12-22
相关资源
最近更新 更多