'undefined' 以某种方式破坏了承诺树
'undefined' somehow breaking promise tree
我是 运行 一个 Node.js/Express
应用程序。在这段代码中,我有一个函数接受来自 'form' 的数据来注册 'new user'。此函数获取输入的用户信息并执行一些任务,例如检查非法字符、检查以确定输入的电子邮件是否已存在于数据库中、'hashes' 输入的名称和密码,最后写入 ( PostGres) 数据库 'new' 用户信息。所有这些代码都被格式化为 'promise tree' 因此每个任务都是按顺序完成的,一个接一个。代码如下:
//server.js
const db = require('./routes/queries');
const traffic = require('./routes/traffic');
...
app.post('/_register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var newHash, newName;
var newToken = shortid.generate();
var client = req.body.user_email;
var creds = req.body.user_password;
var firstname = req.body.user_name;
db.sanitation(client, creds, firstname).then(function (direction) {
console.log('USER-SUPPLIED DATA HAS PASSED INSPECTION');
return db.checkEmail(client); //<==call database query here to check for existing email
}).then(function (founduser) {
if (typeof foundUser != "undefined") {
console.log('HEY THERE IS ALREADY A USER WITH THAT EMAIL!', foundUser);
if (founduser.status === "active") {res.redirect('/client_login'); }
return Promise.reject("Email EXTANT"); //break out of promise chain...to prevent additional code processing below...
} else {
console.log('USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...UNDEFINED!!!'); //appears in log
return traffic.hashPassword(creds); //hash password and continue processing code below...
} //'foundUser' is 'undefined'...OR NOT...
}).then(function (hashedPassword) {
console.log('PASSWORD HASHED'); //does NOT appear in logs
newHash = hashedPassword;
return traffic.hashUsername(firstname);
}).then(function (hashedName) {
console.log('NAME HASHED'); //does NOT appear in logs
newName = hashedName;
return db.createUser(newName, client, newHash, newToken);
}).then(function (data) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
},
function(error) {
console.log('USER REGISTRATION FAILURE...'); //<==THIS MESSAGE SHOWS IN 'LOGS'...WHY???
}
).then(function () {
res.redirect('/landing'); //this page re-direction DOES occur...
}).catch(function (err) {
console.log('THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING...' + error);
res.redirect('/');
});
}); //POST 'register' is used to register NEW users...
这是我的问题。当执行此代码并且用户电子邮件不在数据库中时,在我的日志中我看到消息“用户电子邮件当前不在数据库中......因此它没问题......未定义!!!” ...这是意料之中的,因为电子邮件不在数据库中。从这一点开始,代码应该继续处理,首先是 'hashing' 用户密码,然后继续向下 'promise tree'.
实际上发生的是用户密码和名称的 'hashing' 似乎没有发生...因为我没有看到表明它们已执行的日志消息。相反,我在日志中看到以下消息“USER REGISTRATION FAILURE...”,它表示 'failure'(拒绝)代码写入数据库。
我的问题是为什么我检查来自“checkEmail”函数的 'undefined' 响应的部分似乎没有执行我在其中的代码('return traffic.hashPassword(creds);' 函数)然后随后抛出'reject'后面的代码在'return db.createUser'.
这对我来说完全没有意义。似乎检查数据库中现存用户电子邮件的 'undefined' 响应阻止了代码其余部分的执行,并且莫名其妙地抛出 'rejection' 数据库写入。
这让我很难受。我花了大约一个星期的时间,但我似乎离解决这个问题还差得很远。如果我处理来自 'checkEmail' 调用的 'undefined' return 的代码在某种程度上不正确,有人可以演示执行此操作的正确方法吗?非常感谢任何建议。
我在上面的代码中做了注释,以说明我的日志中显示的内容和未显示的内容
更新:
根据收到的反馈,我使用两种不同的方法重写了上面的代码。这是第一个:
app.post('/register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var newHash, newName;
var client = req.body.client_email;
var creds = req.body.client_password;
var newToken = shortid.generate();
var firstname = req.body.client_name;
try {
const users = db.checkEmail(client);
users.then(function(result) {
console.log('FINAL RESULT ROWS ARE: ' + result.rows)
if (typeof result.rows != "undefined") {
console.log('HEY THERE IS ALREADY A USER WITH THAT EMAIL!');
if (result.status === "active") {
console.log("Email EXTANT");
return res.redirect("/client_login");
} //"active"
} else {
console.log('USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...');
return traffic.hashPassword(creds);
} //'result.rows' is 'undefined'...OR NOT...
})
.then(function(result) {
console.log('PASSWORD HASHED');
console.log(result);
newHash = result;
return traffic.hashUsername(firstname);
})
.then(function(result) {
console.log('NAME HASHED');
newName = result;
return db.createUser(newName, client, newHash, newToken);
})
.then(function(result) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
})
.then(function(result) {
res.redirect('/landing'); //route to 'landing' page...
});
} catch(err) {
// handle errors
console.log('ERROR IN TRY/CATCH IS: ' + err);
}
}); //POST 'register' is used to register NEW clients...
此代码是有效的,但它总是报告 'email' 不在数据库中......即使实际上它是。这是输出日志:
FINAL RESULT ROWS ARE: undefined
USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...
PASSWORD HASHED
b$vW3.YkPyoB9MG5k9qiGreOQC05rWsEIO6i.NkYg6oFqJ8byNjp.iu
NAME HASHED
REGISTERED A NEW CLIENT JOIN...!!!
这是第二个代码块,在函数中使用 'async/await':
app.post('/register', async function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var newHash, newName;
var client = req.body.client_email;
var creds = req.body.client_password;
var newToken = shortid.generate();
var firstname = req.body.client_name;
try {
//const direction = await db.sanitation(client, creds, firstname);
const founduser = await db.checkEmail(client);
console.log('founduser ROWS ARE: ' + founduser.rows)
if (typeof foundUser != "undefined") {
console.log("HEY THERE IS ALREADY A USER WITH THAT EMAIL!", foundUser);
if (founduser.status === "active") {
console.log("Email EXTANT");
return res.redirect("/client_login");
}
} //NOT "undefined"
console.log("USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...!!!");
} catch (err) {
console.log("THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING OF THE TRY STATEMENT..." + err);
return res.redirect("/");
}
}); //POST 'register' is used to register NEW clients...
这段代码也可以正常工作,但是与第一段代码一样,它总是报告 'email' 不在数据库中……即使实际上是这样。这是输出日志:
USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...!!!
根据这些结果,我相信任何一个代码块都可能起作用......并且所有执行报告电子邮件为 'undefined' 的原因(即使它已经存在于数据库中)是因为的“checkEmail”功能。我可能把它错误地写成了正确的 return 和 'async' 结果。这是代码:
const Pool = require('pg').Pool;
const pool = new Pool({
user: 'postgres',
host: '127.0.0.1',
database: 'myDB',
password: 'password',
})
const checkEmail = async function(mail) {
return new Promise(function(resolve, reject) {
pool.query('SELECT * FROM clients WHERE email = ', [mail], function(error, results) {
if (error) {
reject(new Error('Error processing a database check for email!'));
} else {
resolve(results.rows);
}
console.log('checkEmail mail: ' + mail);
console.log('checkEmail results.rows: ' + results.rows);
}) //pool.query
}); //new promise
}
是否有人能够证实我的怀疑,上面的“try/catch”代码块都写得正确......而且调用的问题总是returning“undefined”在“checkEmail”函数中?而且,如果是这样的话……也许建议我需要如何更正“checkEmail”功能,以便在必要时正确地找到数据库中的现有电子邮件。我不太熟悉 'async' 函数的用法,也从未尝试过在查询数据库的承诺中使用它们。提前感谢您的回复。
UPDATE/SOLUTION:
当我第一次编写“checkEmail”promise 函数时,我假设如果在数据库中发现了匹配的电子邮件,它将 'resolve'...如果没有,则 'reject'。我遇到的是该函数始终 'resolves',即使电子邮件不在数据库中也是如此。因此,我发现 'object.keys' 方法的用法对于检查实际上是否有一些数据 return 从函数中编辑很有用。使用它我可以编写现在看起来可以正常运行的代码。这是我当前的“checkEmail”功能:
//queries.js
const checkEmail = async function(mail) {
return new Promise(function(resolve, reject) {
pool.query('SELECT * FROM clients WHERE email = ', [mail], function(error, results) {
if (error) {
reject(new Error('Error processing a database check for email!'));
} else {
resolve(results.rows);
}
console.log('checkEmail mail: ' + mail);
console.log('checkEmail results.rows: ' + results.rows);
}) //pool.query
}); //new promise
}
module.exports = {
...
checkEmail,
...
}
还有我的承诺树:
//server.js
app.post('/register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var client = req.body.client_email;
var creds = req.body.client_password;
var newToken = shortid.generate();
var firstname = req.body.client_name;
db.sanitation(client, creds, firstname)
.then(function (direction) {
console.log('Result direction Object.keys from SANITATION: ', Object.keys(direction).length);
console.log('USER-SUPPLIED DATA HAS PASSED INSPECTION');
return db.checkEmail(client); // <==call database query here to check for existing email for existing email
})
.then(function (founduser) {
console.log('foundUser matching email in database: ', founduser);
console.log('foundUser Object.keys matching email in database: ', Object.keys(founduser).length);
if (Object.keys(founduser).length > 0) {
console.log('EMAIL IS EXTANT IN DATABASE ALREADY!');
if (founduser.length) {console.log('foundUser LENGTH matching email in database: ', founduser.length);}
if (founduser[0].status === 'active') {
console.log('USER-SUPPLIED EMAIL EQUALS THAT OF AN ACTIVE USER');
throw new Error('active'); //break out of promise chain...to prevent additional code processing below...
} else {
console.log('USER-SUPPLIED EMAIL APPEARS IN THE DATABASE');
throw new Error('Email EXTANT'); //break out of promise chain...to prevent additional code processing below...
} //founduser[0].status
} //founduser.length EXCEEDS "0"
if (Object.keys(founduser).length === 0) {
console.log('EMAIL IS NOT PRESENT IN THE DATABASE!');
return traffic.hashPassword(creds); // hash password and continue processing code below...
} //founduser.length EQUALS "0"
})
.then(function (hashedPassword) {
console.log('PASSWORD HASHED');
return traffic.hashUsername(firstname)
.then(function (hashedName) { // nested to keep hashedPassword within scope
console.log('NAME HASHED');
return db.createUser(hashedName, client, hashedPassword, newToken)
.catch(function (error) { // nested in order to catch only an error arising from db.createUser(), (not necessary other than to log out an error message).
console.log('USER REGISTRATION FAILURE...'); // this message will appear only if db.createUser() fails
throw error; // RETHROW error in order to jump to the terminal catch (and hit the `default` case).
});
});
})
.then(function (data) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
res.redirect('/landing'); // success
})
.catch(function (err) {
switch(err.message) {
case 'active':
res.redirect('/client_login');
break;
case 'Email EXTANT':
res.redirect('/client_login');
break;
default: // all unexpected errors
console.log('THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING... ' + err.message);
res.redirect('/');
}
});
}); //POST 'register' is used to register NEW clients...
我要感谢那些对此做出回应的人 post。我非常感谢他们的时间和建议,使我能够了解现在显然是功能代码的这一点。此外,这些回复非常有启发性,我从收到的帮助中学到了一些新技巧。
我认为问题是return Promise.reject("Email EXTANT");
。如果你想中断执行,你可以使用 return res
代替。
使用 asyn/await 方法尝试下面的示例。
编辑:添加检查电子邮件更新
//server.js
const db = require("./routes/queries");
const traffic = require("./routes/traffic");
app.post("/_register", async function (req, res) {
if (!req.body) {
console.log("ERROR: req.body has NOT been returned...");
return res.sendStatus(400);
}
var newToken = shortid.generate();
var client = req.body.user_email;
var creds = req.body.user_password;
var firstname = req.body.user_name;
try {
const direction = await db.sanitation(client, creds, firstname);
const foundusers = await db.checkEmail(client);
if (foundusers.length) {
console.log(
"HEY THERE IS ALREADY A USER WITH THAT EMAIL!",
foundusers[0]
);
if (foundusers[0].status === "active") {
console.log("Email EXTANT");
return res.redirect("/client_login");
}
}
console.log(
"USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...UNDEFINED!!!"
);
const hashedPassword = await traffic.hashPassword(creds);
console.log("PASSWORD HASHED");
const hashedName = await traffic.hashUsername(firstname);
await db.createUser(hashedName, client, hashedPassword, newToken);
console.log("REGISTERED A NEW CLIENT JOIN...!!!");
return res.redirect("/landing");
} catch (err) {
console.log("THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING..." + err);
return res.redirect("/");
}
});
我更新了 checkEmail 函数。
提醒:您应该创建一个 db.js 来导出池,而不是在 checkEmail.js 文件中创建一个池。然后当你需要在其他函数中查询时,他们可以从中导入池而不是重新创建一个新池。
const Pool = require("pg").Pool;
const pool = new Pool({
user: "postgres",
host: "127.0.0.1",
database: "myDB",
password: "password",
});
export const checkEmail = async function (mail) {
try {
const res = await pool.query("SELECT * FROM clients WHERE email = ", [
mail,
]);
console.log(res);
return res.rows;
} catch (err) {
throw err;
}
};
我想知道您是否可能遗漏了以下控制 promise 链错误的基本原则中的一项或多项:
- 如果捕获到一个错误并且您不希望它被标记为已处理(例如,如果您捕获一个错误只是为了记录它)那么您必须重新抛出错误(或抛出您自己的错误)以便沿着承诺链的错误路径继续前进。
- 如果错误被捕获并且没有重新抛出,那么 promise 链将沿着它的成功路径前进。如果未明确返回值,则
undefined
将传递到下一步。
- 自然发生或故意抛出的错误将传播到下一个符合条件的
.catch()
。
- 给定链中的
.catch()
将捕获任何较早的错误,而不仅仅是前一步骤引起的错误。
- a
.catch()
以 .then(successHander, errorHandler)
的形式编写将捕获链中前面步骤的错误,但不会捕获 successHander 的错误。这可能很有用(但在这里没有用)。
- a
.catch()
通常可以通过将其嵌套在主链中使其成为“私有”(即特定于特定的异步步骤)。这避免了捕获链中早期出现的错误。
- 在 promise 链中抛出错误比
return Promise.reject(...)
更经济。
您可以将重定向嵌入链中,但我建议在终端 .catch()
中抛出错误和分支会更清晰(例如使用 switch/case 结构)。
您最终可能会得到这样的结果(代码中有大量注释)...
//server.js
const db = require('./routes/queries');
const traffic = require('./routes/traffic');
...
app.post('/_register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
// var newHash, newName; // not needed
var newToken = shortid.generate();
var client = req.body.user_email;
var creds = req.body.user_password;
var firstname = req.body.user_name;
db.sanitation(client, creds, firstname)
.then(function (direction) {
console.log('USER-SUPPLIED DATA HAS PASSED INSPECTION');
return db.checkEmail(client); // <==call database query here to check for existing email
})
.then(function (founduser) {
if (typeof foundUser != "undefined") { // not a particularly good test, maybe if(foundUser) {...} would be better?
console.log('HEY THERE IS ALREADY A USER WITH THAT EMAIL!', foundUser);
if (founduser.status === 'active') {
throw new Error('active'); // break out of promise chain...to prevent additional code processing below...
} else {
throw new Error('Email EXTANT'); // break out of promise chain...to prevent additional code processing below...
}
} else {
console.log('USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...UNDEFINED!!!'); // appears in log
return traffic.hashPassword(creds); // hash password and continue processing code below...
}
})
.then(function (hashedPassword) {
console.log('PASSWORD HASHED');
return traffic.hashUsername(firstname)
.then(function (hashedName) { // nested to keep hashedPassword within scope
console.log('NAME HASHED');
return db.createUser(hashedName, client, hashedPassword, newToken)
.catch(function (error) { // nested in order to catch only an error arising from db.createUser(), (not necessary other than to log out an error message).
console.log('USER REGISTRATION FAILURE...'); // this message will appear only if db.createUser() fails
throw error; // RETHROW error in order to jump to the terminal catch (and hit the `default` case).
});
});
})
.then(function (data) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
res.redirect('/landing'); // success
})
.catch(function (err) {
// Suggest you perform all error case redirects here, depending on which error occurred.
// May not be 100% correct but you get the idea.
switch(err.message) {
case 'active':
res.redirect('/client_login');
break;
case 'Email EXTANT':
default: // all unexpected errors
console.log('THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING... ' + err.message);
res.redirect('/');
}
});
}); // POST 'register' is used to register NEW users...
我是 运行 一个 Node.js/Express
应用程序。在这段代码中,我有一个函数接受来自 'form' 的数据来注册 'new user'。此函数获取输入的用户信息并执行一些任务,例如检查非法字符、检查以确定输入的电子邮件是否已存在于数据库中、'hashes' 输入的名称和密码,最后写入 ( PostGres) 数据库 'new' 用户信息。所有这些代码都被格式化为 'promise tree' 因此每个任务都是按顺序完成的,一个接一个。代码如下:
//server.js
const db = require('./routes/queries');
const traffic = require('./routes/traffic');
...
app.post('/_register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var newHash, newName;
var newToken = shortid.generate();
var client = req.body.user_email;
var creds = req.body.user_password;
var firstname = req.body.user_name;
db.sanitation(client, creds, firstname).then(function (direction) {
console.log('USER-SUPPLIED DATA HAS PASSED INSPECTION');
return db.checkEmail(client); //<==call database query here to check for existing email
}).then(function (founduser) {
if (typeof foundUser != "undefined") {
console.log('HEY THERE IS ALREADY A USER WITH THAT EMAIL!', foundUser);
if (founduser.status === "active") {res.redirect('/client_login'); }
return Promise.reject("Email EXTANT"); //break out of promise chain...to prevent additional code processing below...
} else {
console.log('USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...UNDEFINED!!!'); //appears in log
return traffic.hashPassword(creds); //hash password and continue processing code below...
} //'foundUser' is 'undefined'...OR NOT...
}).then(function (hashedPassword) {
console.log('PASSWORD HASHED'); //does NOT appear in logs
newHash = hashedPassword;
return traffic.hashUsername(firstname);
}).then(function (hashedName) {
console.log('NAME HASHED'); //does NOT appear in logs
newName = hashedName;
return db.createUser(newName, client, newHash, newToken);
}).then(function (data) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
},
function(error) {
console.log('USER REGISTRATION FAILURE...'); //<==THIS MESSAGE SHOWS IN 'LOGS'...WHY???
}
).then(function () {
res.redirect('/landing'); //this page re-direction DOES occur...
}).catch(function (err) {
console.log('THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING...' + error);
res.redirect('/');
});
}); //POST 'register' is used to register NEW users...
这是我的问题。当执行此代码并且用户电子邮件不在数据库中时,在我的日志中我看到消息“用户电子邮件当前不在数据库中......因此它没问题......未定义!!!” ...这是意料之中的,因为电子邮件不在数据库中。从这一点开始,代码应该继续处理,首先是 'hashing' 用户密码,然后继续向下 'promise tree'.
实际上发生的是用户密码和名称的 'hashing' 似乎没有发生...因为我没有看到表明它们已执行的日志消息。相反,我在日志中看到以下消息“USER REGISTRATION FAILURE...”,它表示 'failure'(拒绝)代码写入数据库。
我的问题是为什么我检查来自“checkEmail”函数的 'undefined' 响应的部分似乎没有执行我在其中的代码('return traffic.hashPassword(creds);' 函数)然后随后抛出'reject'后面的代码在'return db.createUser'.
这对我来说完全没有意义。似乎检查数据库中现存用户电子邮件的 'undefined' 响应阻止了代码其余部分的执行,并且莫名其妙地抛出 'rejection' 数据库写入。
这让我很难受。我花了大约一个星期的时间,但我似乎离解决这个问题还差得很远。如果我处理来自 'checkEmail' 调用的 'undefined' return 的代码在某种程度上不正确,有人可以演示执行此操作的正确方法吗?非常感谢任何建议。
我在上面的代码中做了注释,以说明我的日志中显示的内容和未显示的内容
更新:
根据收到的反馈,我使用两种不同的方法重写了上面的代码。这是第一个:
app.post('/register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var newHash, newName;
var client = req.body.client_email;
var creds = req.body.client_password;
var newToken = shortid.generate();
var firstname = req.body.client_name;
try {
const users = db.checkEmail(client);
users.then(function(result) {
console.log('FINAL RESULT ROWS ARE: ' + result.rows)
if (typeof result.rows != "undefined") {
console.log('HEY THERE IS ALREADY A USER WITH THAT EMAIL!');
if (result.status === "active") {
console.log("Email EXTANT");
return res.redirect("/client_login");
} //"active"
} else {
console.log('USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...');
return traffic.hashPassword(creds);
} //'result.rows' is 'undefined'...OR NOT...
})
.then(function(result) {
console.log('PASSWORD HASHED');
console.log(result);
newHash = result;
return traffic.hashUsername(firstname);
})
.then(function(result) {
console.log('NAME HASHED');
newName = result;
return db.createUser(newName, client, newHash, newToken);
})
.then(function(result) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
})
.then(function(result) {
res.redirect('/landing'); //route to 'landing' page...
});
} catch(err) {
// handle errors
console.log('ERROR IN TRY/CATCH IS: ' + err);
}
}); //POST 'register' is used to register NEW clients...
此代码是有效的,但它总是报告 'email' 不在数据库中......即使实际上它是。这是输出日志:
FINAL RESULT ROWS ARE: undefined
USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...
PASSWORD HASHED
b$vW3.YkPyoB9MG5k9qiGreOQC05rWsEIO6i.NkYg6oFqJ8byNjp.iu
NAME HASHED
REGISTERED A NEW CLIENT JOIN...!!!
这是第二个代码块,在函数中使用 'async/await':
app.post('/register', async function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var newHash, newName;
var client = req.body.client_email;
var creds = req.body.client_password;
var newToken = shortid.generate();
var firstname = req.body.client_name;
try {
//const direction = await db.sanitation(client, creds, firstname);
const founduser = await db.checkEmail(client);
console.log('founduser ROWS ARE: ' + founduser.rows)
if (typeof foundUser != "undefined") {
console.log("HEY THERE IS ALREADY A USER WITH THAT EMAIL!", foundUser);
if (founduser.status === "active") {
console.log("Email EXTANT");
return res.redirect("/client_login");
}
} //NOT "undefined"
console.log("USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...!!!");
} catch (err) {
console.log("THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING OF THE TRY STATEMENT..." + err);
return res.redirect("/");
}
}); //POST 'register' is used to register NEW clients...
这段代码也可以正常工作,但是与第一段代码一样,它总是报告 'email' 不在数据库中……即使实际上是这样。这是输出日志:
USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...!!!
根据这些结果,我相信任何一个代码块都可能起作用......并且所有执行报告电子邮件为 'undefined' 的原因(即使它已经存在于数据库中)是因为的“checkEmail”功能。我可能把它错误地写成了正确的 return 和 'async' 结果。这是代码:
const Pool = require('pg').Pool;
const pool = new Pool({
user: 'postgres',
host: '127.0.0.1',
database: 'myDB',
password: 'password',
})
const checkEmail = async function(mail) {
return new Promise(function(resolve, reject) {
pool.query('SELECT * FROM clients WHERE email = ', [mail], function(error, results) {
if (error) {
reject(new Error('Error processing a database check for email!'));
} else {
resolve(results.rows);
}
console.log('checkEmail mail: ' + mail);
console.log('checkEmail results.rows: ' + results.rows);
}) //pool.query
}); //new promise
}
是否有人能够证实我的怀疑,上面的“try/catch”代码块都写得正确......而且调用的问题总是returning“undefined”在“checkEmail”函数中?而且,如果是这样的话……也许建议我需要如何更正“checkEmail”功能,以便在必要时正确地找到数据库中的现有电子邮件。我不太熟悉 'async' 函数的用法,也从未尝试过在查询数据库的承诺中使用它们。提前感谢您的回复。
UPDATE/SOLUTION:
当我第一次编写“checkEmail”promise 函数时,我假设如果在数据库中发现了匹配的电子邮件,它将 'resolve'...如果没有,则 'reject'。我遇到的是该函数始终 'resolves',即使电子邮件不在数据库中也是如此。因此,我发现 'object.keys' 方法的用法对于检查实际上是否有一些数据 return 从函数中编辑很有用。使用它我可以编写现在看起来可以正常运行的代码。这是我当前的“checkEmail”功能:
//queries.js
const checkEmail = async function(mail) {
return new Promise(function(resolve, reject) {
pool.query('SELECT * FROM clients WHERE email = ', [mail], function(error, results) {
if (error) {
reject(new Error('Error processing a database check for email!'));
} else {
resolve(results.rows);
}
console.log('checkEmail mail: ' + mail);
console.log('checkEmail results.rows: ' + results.rows);
}) //pool.query
}); //new promise
}
module.exports = {
...
checkEmail,
...
}
还有我的承诺树:
//server.js
app.post('/register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var client = req.body.client_email;
var creds = req.body.client_password;
var newToken = shortid.generate();
var firstname = req.body.client_name;
db.sanitation(client, creds, firstname)
.then(function (direction) {
console.log('Result direction Object.keys from SANITATION: ', Object.keys(direction).length);
console.log('USER-SUPPLIED DATA HAS PASSED INSPECTION');
return db.checkEmail(client); // <==call database query here to check for existing email for existing email
})
.then(function (founduser) {
console.log('foundUser matching email in database: ', founduser);
console.log('foundUser Object.keys matching email in database: ', Object.keys(founduser).length);
if (Object.keys(founduser).length > 0) {
console.log('EMAIL IS EXTANT IN DATABASE ALREADY!');
if (founduser.length) {console.log('foundUser LENGTH matching email in database: ', founduser.length);}
if (founduser[0].status === 'active') {
console.log('USER-SUPPLIED EMAIL EQUALS THAT OF AN ACTIVE USER');
throw new Error('active'); //break out of promise chain...to prevent additional code processing below...
} else {
console.log('USER-SUPPLIED EMAIL APPEARS IN THE DATABASE');
throw new Error('Email EXTANT'); //break out of promise chain...to prevent additional code processing below...
} //founduser[0].status
} //founduser.length EXCEEDS "0"
if (Object.keys(founduser).length === 0) {
console.log('EMAIL IS NOT PRESENT IN THE DATABASE!');
return traffic.hashPassword(creds); // hash password and continue processing code below...
} //founduser.length EQUALS "0"
})
.then(function (hashedPassword) {
console.log('PASSWORD HASHED');
return traffic.hashUsername(firstname)
.then(function (hashedName) { // nested to keep hashedPassword within scope
console.log('NAME HASHED');
return db.createUser(hashedName, client, hashedPassword, newToken)
.catch(function (error) { // nested in order to catch only an error arising from db.createUser(), (not necessary other than to log out an error message).
console.log('USER REGISTRATION FAILURE...'); // this message will appear only if db.createUser() fails
throw error; // RETHROW error in order to jump to the terminal catch (and hit the `default` case).
});
});
})
.then(function (data) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
res.redirect('/landing'); // success
})
.catch(function (err) {
switch(err.message) {
case 'active':
res.redirect('/client_login');
break;
case 'Email EXTANT':
res.redirect('/client_login');
break;
default: // all unexpected errors
console.log('THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING... ' + err.message);
res.redirect('/');
}
});
}); //POST 'register' is used to register NEW clients...
我要感谢那些对此做出回应的人 post。我非常感谢他们的时间和建议,使我能够了解现在显然是功能代码的这一点。此外,这些回复非常有启发性,我从收到的帮助中学到了一些新技巧。
我认为问题是return Promise.reject("Email EXTANT");
。如果你想中断执行,你可以使用 return res
代替。
使用 asyn/await 方法尝试下面的示例。
编辑:添加检查电子邮件更新
//server.js
const db = require("./routes/queries");
const traffic = require("./routes/traffic");
app.post("/_register", async function (req, res) {
if (!req.body) {
console.log("ERROR: req.body has NOT been returned...");
return res.sendStatus(400);
}
var newToken = shortid.generate();
var client = req.body.user_email;
var creds = req.body.user_password;
var firstname = req.body.user_name;
try {
const direction = await db.sanitation(client, creds, firstname);
const foundusers = await db.checkEmail(client);
if (foundusers.length) {
console.log(
"HEY THERE IS ALREADY A USER WITH THAT EMAIL!",
foundusers[0]
);
if (foundusers[0].status === "active") {
console.log("Email EXTANT");
return res.redirect("/client_login");
}
}
console.log(
"USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...UNDEFINED!!!"
);
const hashedPassword = await traffic.hashPassword(creds);
console.log("PASSWORD HASHED");
const hashedName = await traffic.hashUsername(firstname);
await db.createUser(hashedName, client, hashedPassword, newToken);
console.log("REGISTERED A NEW CLIENT JOIN...!!!");
return res.redirect("/landing");
} catch (err) {
console.log("THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING..." + err);
return res.redirect("/");
}
});
我更新了 checkEmail 函数。
提醒:您应该创建一个 db.js 来导出池,而不是在 checkEmail.js 文件中创建一个池。然后当你需要在其他函数中查询时,他们可以从中导入池而不是重新创建一个新池。
const Pool = require("pg").Pool;
const pool = new Pool({
user: "postgres",
host: "127.0.0.1",
database: "myDB",
password: "password",
});
export const checkEmail = async function (mail) {
try {
const res = await pool.query("SELECT * FROM clients WHERE email = ", [
mail,
]);
console.log(res);
return res.rows;
} catch (err) {
throw err;
}
};
我想知道您是否可能遗漏了以下控制 promise 链错误的基本原则中的一项或多项:
- 如果捕获到一个错误并且您不希望它被标记为已处理(例如,如果您捕获一个错误只是为了记录它)那么您必须重新抛出错误(或抛出您自己的错误)以便沿着承诺链的错误路径继续前进。
- 如果错误被捕获并且没有重新抛出,那么 promise 链将沿着它的成功路径前进。如果未明确返回值,则
undefined
将传递到下一步。 - 自然发生或故意抛出的错误将传播到下一个符合条件的
.catch()
。 - 给定链中的
.catch()
将捕获任何较早的错误,而不仅仅是前一步骤引起的错误。 - a
.catch()
以.then(successHander, errorHandler)
的形式编写将捕获链中前面步骤的错误,但不会捕获 successHander 的错误。这可能很有用(但在这里没有用)。 - a
.catch()
通常可以通过将其嵌套在主链中使其成为“私有”(即特定于特定的异步步骤)。这避免了捕获链中早期出现的错误。 - 在 promise 链中抛出错误比
return Promise.reject(...)
更经济。
您可以将重定向嵌入链中,但我建议在终端 .catch()
中抛出错误和分支会更清晰(例如使用 switch/case 结构)。
您最终可能会得到这样的结果(代码中有大量注释)...
//server.js
const db = require('./routes/queries');
const traffic = require('./routes/traffic');
...
app.post('/_register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
// var newHash, newName; // not needed
var newToken = shortid.generate();
var client = req.body.user_email;
var creds = req.body.user_password;
var firstname = req.body.user_name;
db.sanitation(client, creds, firstname)
.then(function (direction) {
console.log('USER-SUPPLIED DATA HAS PASSED INSPECTION');
return db.checkEmail(client); // <==call database query here to check for existing email
})
.then(function (founduser) {
if (typeof foundUser != "undefined") { // not a particularly good test, maybe if(foundUser) {...} would be better?
console.log('HEY THERE IS ALREADY A USER WITH THAT EMAIL!', foundUser);
if (founduser.status === 'active') {
throw new Error('active'); // break out of promise chain...to prevent additional code processing below...
} else {
throw new Error('Email EXTANT'); // break out of promise chain...to prevent additional code processing below...
}
} else {
console.log('USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...UNDEFINED!!!'); // appears in log
return traffic.hashPassword(creds); // hash password and continue processing code below...
}
})
.then(function (hashedPassword) {
console.log('PASSWORD HASHED');
return traffic.hashUsername(firstname)
.then(function (hashedName) { // nested to keep hashedPassword within scope
console.log('NAME HASHED');
return db.createUser(hashedName, client, hashedPassword, newToken)
.catch(function (error) { // nested in order to catch only an error arising from db.createUser(), (not necessary other than to log out an error message).
console.log('USER REGISTRATION FAILURE...'); // this message will appear only if db.createUser() fails
throw error; // RETHROW error in order to jump to the terminal catch (and hit the `default` case).
});
});
})
.then(function (data) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
res.redirect('/landing'); // success
})
.catch(function (err) {
// Suggest you perform all error case redirects here, depending on which error occurred.
// May not be 100% correct but you get the idea.
switch(err.message) {
case 'active':
res.redirect('/client_login');
break;
case 'Email EXTANT':
default: // all unexpected errors
console.log('THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING... ' + err.message);
res.redirect('/');
}
});
}); // POST 'register' is used to register NEW users...