正确处理Node Promise中的asynchronousMongo操作

我有一个执行多个Mongo操作的函数,最后一个操作是在所有其他操作完成后closures数据库。 我对这个问题的处理相当有信心,但是我有一些外部的意见引起了关注,我想validation我的解决scheme是否正确。

build议的解决scheme:

function updateDatabase (name, token) { return new Promise((resolve, reject) => { MongoClient.connect(MONGODB_URL) .then( (database) => { return database.collection('testCollection').update({name}, {$pull: {tokens: {$in: [token]}}}) .then( () => { database.collection('log').insert({ name, token }); return database; }) }) .then( (db) => { db.close(true); resolve(`Invalid token: ${token} has been removed from: ${name}`); }) .catch( (err) => { reject(err); }) }); } 

我原来的解决scheme

 function updateDatabase (name, token) { return new Promise((resolve, reject) => { MongoClient.connect(MONGODB_URL) .then( (database) => { return database; }) .then( (db) => { database.collection('testCollection').update({name}, {$pull: {tokens: {$in: [token]}}}) return database; }) .then( () => { database.collection('log').insert({ name, token }); return database; }) .then( (db) => { db.close(true); resolve(`Invalid token: ${token} has been removed from: ${name}`); }) .catch( (err) => { reject(err); }) }); } 

我的原始解决scheme是不是商标或build议的解决scheme更好的方法? 两个工作在testing,但对生产等级的负载,我需要确保数据库不会closures,直到其他行动完成,我相信我已经完成了我原来的解决scheme。

由于MongoDB驱动程序的所有asynchronous操作都已经返回一个promise,所以不应该使用new Promise ,而是设置一个promise链:

 function updateDatabase(name, token) { let database; return MongoClient.connect(MONGODB_URL).then(db => { database = db; return database .collection("testCollection") .update({ name }, { $pull: { tokens: { $in: [token] } } }); }) .then(() => { return database.collection("log").insert({ name, token }); }) .then(() => { database.close(true); }) .catch(err => { database.close(true); throw err; }); } 

我知道你想传递database作为下一个参数,但是你会遇到这个问题,它不会在catch处理程序中可用。 一种解决scheme是使用一个函数范围的variables,在打开连接之后得到分配,就像上面的代码一样。

如果你不喜欢,你可以在MongoClient.connect处理程序中创build一个新的promise链:

 function updateDatabase(name, token) { return MongoClient.connect(MONGODB_URL).then(database => { return database .collection("testCollection") .update({ name }, { $pull: { tokens: { $in: [token] } } }) .then(() => { return database.collection("log").insert({ name, token }); }) .then(() => { database.close(true); }) .catch(err => { database.close(true); throw err; }); }); } 

我试图概述原始代码的一些主要问题:

 function updateDatabase (name, token) { //useless. MongoClient.connect already returns the promise return new Promise((resolve, reject) => { MongoClient.connect(MONGODB_URL) .then( (database) => { // useless. The function does nothing and can be removed return database; }) .then( (db) => { // should be db, not database // update is async. Should be added to the chain. database.collection('testCollection').update({name}, {$pull: {tokens: {$in: [token]}}}) // what's the point to return database, if the following function does not accept any parameters return database; }) .then( () => { // insert is async. Should be added to the chain. database.collection('log').insert({ name, token }); return database; }) .then( (db) => { // close is async. Should be added to the chain. db.close(true); resolve(`Invalid token: ${token} has been removed from: ${name}`); }) .catch( (err) => { reject(err); }) }); } 

所以这个函数应该看起来像这样:

 function updateDatabase (name, token) { return MongoClient.connect(MONGODB_URL) .then( db => db.collection('testCollection').update({name}, {$pull: {tokens: {$in: [token]}}}) .then(()=>db) }) .then( db => db.collection('log').insert({name, token}) .then(()=>db) }) .then( db => db.close(true)) .then(()=>`Invalid token: ${token} has been removed from: ${name}`); } 

如果查询顺序无关紧要,您可以从Promise.all

 function updateDatabase (name, token) { return MongoClient.connect(MONGODB_URL) .then( db => Promise.all([ Promise.resolve(db), db.collection('testCollection').update({name}, {$pull: {tokens: {$in: [token]}}}), db.collection('log').insert({name, token}), ]) .then( ([db]) => db.close(true)) .then(()=>`Invalid token: ${token} has been removed from: ${name}`); } 

这两个解决scheme的共同问题是,然后(function)处理程序。 处理程序返回数据库,而不是为MongoDB操作返回Promise,因此将调用下一个链处理程序不等待MongoDB操作完成。 相反,承诺的MongoDB操作应该按照执行的顺序进行链接。 另外Mongo方法返回Promise,所以不需要新的Promise:

 function updateDatabase (name, token) { return MongoClient.connect(MONGODB_URL) .then( (db) => Promise.all([ db.collection('testCollection').update({name}, {$pull: {tokens: {$in: [token]}}}), db.collection('log').insert({name, token}) ]).then(() => db.close(true) ).then(`Invalid token: ${token} has been removed from: ${name}` ).catch((err) => { db.close(true); throw err }); ) } 

或者使用async / await语法:

 async function updateDatabase (name, token) { let db = await MongoClient.connect(MONGODB_URL); try { await db.collection('testCollection').update({name}, {$pull: {tokens: {$in: [token]}}}); await db.collection('log').insert({name, token}); return `Invalid token: ${token} has been removed from: ${name}`; } finally { await db.close(true); } }