You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用async函数创建新Promise是否属于不良实践?(Node.js MongoDB场景)

关于Promise嵌套async/await的Node.js MongoDB代码实践疑问

我的代码场景

我写了一段Node.js与MongoDB的CRUD应用代码,用来处理带JSON载荷的POST请求,完成数据创建操作。目前代码能正常运行,但我拿不准自己对Promise和async/await的使用是不是属于不良实践,想请教下大家。

我的代码片段

handlers._newbies = {}; 
handlers._newbies.post = (parsedReq, res) => { 
  const newbie = JSON.parse(parsedReq.payload); 
  databaseCalls.create(newbie) 
    .then((result) => { 
      res.writeHead(200,{'Content-Type' : 'application/json'}); 
      const resultToString = JSON.stringify(result.ops[0]); 
      res.write(resultToString); 
      res.end(); 
    }) 
    .catch(err => console.log(err)); 
}; 

const databaseCalls = {}; 
databaseCalls.create = (newbie) => { 
  return new Promise(async (resolve, reject) => { 
    try { 
      const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true }); 
      console.log("Connected correctly to server"); 
      const db = client.db('Noob-List'); 
      const result = await db.collection('newbies').insertOne(newbie); 
      client.close(); 
      resolve(result); 
    } catch(err) { 
      console.log(err); 
    } 
  }); 
};

我的疑问

当时写这段代码时,我希望databaseCalls.create能返回一个包含插入操作结果的Promise,但如果直接返回insertOne的Promise,就没办法调用client.close()了,所以才用了Promise嵌套async/await的写法。但我不确定这种写法合不合适,也没找到相关的明确说明,所以来求助。


解答

首先直接给结论:你当前的写法属于没必要的Promise嵌套,是可以优化的不良实践,下面给你拆解问题和优化方案:

问题出在哪?

async函数本身就会自动返回一个Promise,完全不需要你手动用new Promise()去包裹它。这种嵌套写法不仅冗余,还藏着一个坑:你在内部catch里只打印了错误,但没有调用reject(err),这会导致如果数据库操作出错,这个Promise会一直处于pending状态,外部的.catch()根本捕获不到这个错误!

优化后的写法

直接把databaseCalls.create定义成async函数就行,它会自动帮你处理Promise的返回,同时你照样能完成连接、插入、关闭的流程:

const databaseCalls = {}; 
databaseCalls.create = async (newbie) => { 
  try { 
    const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true }); 
    console.log("Connected correctly to server"); 
    const db = client.db('Noob-List'); 
    const result = await db.collection('newbies').insertOne(newbie); 
    client.close(); 
    return result; // async函数会自动把这个返回值包装成resolved状态的Promise
  } catch(err) { 
    console.log(err); 
    throw err; // 抛出错误,让外部的错误捕获逻辑能拿到这个错误
  } 
};

额外的优化建议

  1. 完善错误传递:刚才提到的原代码错误捕获的问题,优化后用throw err把错误抛出去,这样上层的.catch()或者try/catch就能捕获到,你还可以给客户端返回对应的错误响应,比如500状态码。
  2. 复用数据库连接:每次请求都创建新的MongoDB连接其实很低效,建议在应用启动的时候就创建一次连接,之后所有的数据库操作都复用这个连接,不用每次都打开关闭:
// 应用启动时初始化连接
let dbInstance;
MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true })
  .then(client => {
    console.log("Connected correctly to server");
    dbInstance = client.db('Noob-List');
  })
  .catch(err => console.error('数据库连接失败:', err));

// 之后的创建操作直接复用连接
databaseCalls.create = async (newbie) => { 
  try { 
    const result = await dbInstance.collection('newbies').insertOne(newbie); 
    return result; 
  } catch(err) { 
    console.error('数据插入失败:', err); 
    throw err; 
  } 
};
  1. 处理器也改用async/await:你的请求处理器也可以改成async函数,让代码逻辑更连贯易读,不用再写.then()链式调用:
handlers._newbies.post = async (parsedReq, res) => { 
  try {
    const newbie = JSON.parse(parsedReq.payload); 
    const result = await databaseCalls.create(newbie);
    res.writeHead(200,{'Content-Type' : 'application/json'}); 
    res.write(JSON.stringify(result.ops[0])); 
    res.end();
  } catch(err) {
    console.error('请求处理失败:', err);
    // 给客户端返回错误响应
    res.writeHead(500,{'Content-Type' : 'application/json'});
    res.write(JSON.stringify({error: '服务器内部错误'}));
    res.end();
  }
};

内容的提问来源于stack exchange,提问作者Firecore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:15:31