节点使用promise.catch()语句抛出了猫绿色请求的无用征服者



我是Node/Mongoose的新手,并且正在尝试正确处理脚本中的错误,以将球员添加到联赛中。在以下代码中,明确抛出和与非宣传相关的错误被.catch()语句正确捕获,但拒绝的承诺不是。

例如,尝试传递无效的用户ID抛出User not found

但是,如果我通过断开数据库来测试承诺拒绝,我会得到以下内容:

(node:6252) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017]

我是否正在使用Promise.all()和.catch()或不正确地?

只是要清楚,我正在尝试弄清为什么没有处理错误的原因,而不是为什么要丢弃错误。

我的脚本:

const 
mongoose = require('mongoose'),
User = require('./models/users'),
League = require('./models/leagues'),
dbUrl = process.env.DBURL || 'mongodb://localhost/predictor';
mongoose.connect(dbUrl, { useNewUrlParser: true });
const addUserToLeague = (userId, leagueId) => {
    let foundUser = User.findById(userId);
    let foundLeague = League.findById(leagueId);
    return Promise.all([foundUser, foundLeague])
    .then(arr => {
        if(!arr[0]){
            throw 'User not found';
        }else if(!arr[1]){
            throw 'League not found';
        }
        return arr;
    })
    .then(arr => {
        arr[0].leagueMemberships.push(arr[1]);
        arr[1].users.push(arr[0]);
        return arr;
    })
    .then(updatedArr => {
        updatedArr[0].save();
        updatedArr[1].save();
        return updatedArr;
    })
    .then(updatedArr => { console.log(`User ${updatedArr[0]._id} added to league ${updatedArr[1]._id}`) })
    .catch(err => { console.log('Error:', err) });
};
addUserToLeague(process.argv[2], process.argv[3]); // Needs 2 args: User ID and League ID

正如Bergi指出的那样,该错误似乎来自connect,这返回了您完全没有处理的承诺包括不等待它完成。因此,至少您需要处理:

const connectionPromise = mongoose.connect(dbUrl, { useNewUrlParser: true })
    .catch(error => {
        // Handle connection error
    });

然后在addUserToLeague中:

const addUserToLeague = (userId, leagueId) => {
    return connectionPromise.then(connection => {
        // ...logic here
    });
};

... 但是,我质疑当模块被加载时是否应该连接,而不是将连接传递到addUserToLeague


除此之外,Promise.all的实际使用还可以,但是:

  1. 一个人希望findById不能解决如果找不到该项目,则具有虚假值的承诺,因此整个then处理程序似乎是不必要的。
  2. 大概save返回承诺。您不是要处理拒绝或等待解决方案。
  3. 我会使用破坏性来避免arr[0]arr[1],因为很容易忘记订单。
  4. 没有理由将then处理程序带有push调用与then处理程序分开进行保存的理由。
  5. addUserToLeague应该返回承诺链的结果,以便称呼它a)知道何时完成,b)知道何时失败。
  6. 不应在addUserToLeague中处理错误;而是在呼叫者中处理它们。
  7. 也存在一个问题,即数据是不合同的:您正在将成员信息存储在用户对象和联盟对象中。也许在文档数据库中相对正常(我不知道);在RDBMS中,您将信息存储在A 位置中。从addUserToLeague中的代码中可以明显看出原因:如果保存用户成功但保存联盟失败怎么办?然后,用户对象说这是联盟的成员,联盟对象并不是说它是成员。还有一个问题是,由于它被存储在两个地方,即使没有任何问题,在短时间内(用户或联盟)将保存一个(用户或联盟),但另一个不会保存。两者都是完整性问题。如果您可以将其标准化以将此信息存储在一个地方,那就太好了。如果不能,则需要更新代码,以保存其中一个,等待成功,保存另一个,如果失败会尝试将更改撤消到第一个。

这样的事情(我不尝试在这里解决标准化问题,这是一件大事):

const 
mongoose = require('mongoose'),
User = require('./models/users'),
League = require('./models/leagues'),
dbUrl = process.env.DBURL || 'mongodb://localhost/predictor';
const addUserToLeague = (connection, userId, leagueId) => {
    return Promise.all([
        User.findById(userId),
        League.findById(leagueId)
    ])
    .then(([user, league]) => {
        user.leagueMemberships.push(league);
        league.users.push(user);
        return Promise.all([user.save(), league.save()]);
    })
    .then((([user, league]) => {
        console.log(`User ${user._id} added to league ${league._id}`);
    });
};
mongoose.connect(dbUrl, { useNewUrlParser: true })
.then(connection => addUserToLeague(connection, process.argv[2], process.argv[3]) // Needs 2 args: User ID and League ID
.catch(error => {
    // Handle/report error
});

如果您使用的是任何近期节点的Verson,则可以使用async函数:

const 
mongoose = require('mongoose'),
User = require('./models/users'),
League = require('./models/leagues'),
dbUrl = process.env.DBURL || 'mongodb://localhost/predictor';
const addUserToLeague = async (connection, userId, leagueId) => {
    let [user, league] = await Promise.all([
        User.findById(userId),
        League.findById(leagueId)
    ]);
    user.leagueMemberships.push(league);
    league.users.push(user);
    [user, league] = await Promise.all([user.save(), league.save()]);
    console.log(`User ${user._id} added to league ${league._id}`);
};
mongoose.connect(dbUrl, { useNewUrlParser: true })
.then(connection => addUserToLeague(connection, process.argv[2], process.argv[3]) // Needs 2 args: User ID and League ID
.catch(error => {
    // Handle/report error
});

最新更新