为何不用await时Contact.findByIdAndDelete不删MongoDB数据,而create可新增?
这两种情况的差异本质是偶然的,取决于异步操作的执行速度是否快于响应发送的时机,而非两种方法有本质区别。
核心原理
Mongoose的所有CRUD方法(包括create和findByIdAndDelete)都是异步的,返回Promise。当你不使用await也不通过.then()/.catch()处理Promise时,这些操作会在后台异步执行,但代码会直接跳到res.redirect发送响应,结束当前请求。
为什么create看似"成功"?
Contact.create()是直接向MongoDB插入新文档,不需要预先查询数据,MongoDB处理这类写入请求的速度非常快。通常在res.redirect发送响应之前,Node.js的事件循环已经完成了这个插入操作的回调,所以数据被成功写入数据库。
为什么findByIdAndDelete失败?
Contact.findByIdAndDelete()需要分两步执行:首先根据_id查询目标文档,然后执行删除操作。这个过程比单纯的插入多了一次查询交互,耗时相对更长。当res.redirect发送响应后,当前请求的上下文结束,Node.js的事件循环可能还没轮到处理这个删除操作的Promise回调,导致删除请求还没被MongoDB处理完成,最终表现为数据没有被删除。
重要提醒
这两种写法都是不规范且不可靠的。即使create这次成功了,在高并发或者数据量较大的场景下,也可能出现插入失败的情况。正确的做法是必须使用await等待异步操作完成,或者通过.then()/.catch()处理Promise,确保数据库操作完成后再发送响应:
修正后的POST请求:
app.post('/create',async(req,res)=>{ await Contact.create(req.body); return res.redirect('back'); })
修正后的GET请求:
app.get('/delete',async(req,res)=>{ await Contact.findByIdAndDelete(req.query.id); return res.redirect('back'); })
另外,建议添加错误处理,避免未捕获的Promise拒绝导致服务崩溃:
app.post('/create',async(req,res)=>{ try { await Contact.create(req.body); return res.redirect('back'); } catch (err) { console.error(err); return res.status(500).send('创建联系人失败'); } })
内容的提问来源于stack exchange,提问作者Pankaj Shah

