Nodejsexpression和承诺不做我期望的
我正在尝试使用NodeJS构build一个loginAPI,但是我的代码并没有达到我期望的效果。 我对js,承诺等都很陌生,所以请尽可能简化任何答案。
从我的代码输出中可以看到,第一个promise部分不会等到函数findUsers(...)
完成。
我有一个路线文件,我想依次运行几个函数:
- 查找用户是否存在于数据库中
- 如果(1为真)散列并input密码
- …等
路线文件现在包含:
var loginM = require('../models/login'); var loginC = require('../controllers/login'); var Promise = require('promise'); module.exports = function(app) { app.post('/login/', function(req, res, next) { var promise = new Promise(function (resolve, reject) { var rows = loginM.findUser(req.body, res); if (rows.length > 0) { console.log("Success"); resolve(rows); } else { console.log("Failed"); reject(reason); } }); promise.then(function(data) { return new Promise(function (resolve, reject) { loginC.doSomething(data); if (success) { console.log("Success 2"); resolve(data); } else { console.log("Failed 2"); reject(reason); } }); }, function (reason) { console.log("error handler second"); }); }); }
findUser
函数包含池和查询,并位于模型文件中:
var connection = require('../dbConnection'); var loginC = require('../controllers/login'); function Login() { var me = this; var pool = connection.getPool(); me.findUser = function(params, res) { var username = params.username; pool.getConnection(function (err, connection) { console.log("Connection "); if (err) { console.log("ERROR 1 "); res.send({"code": 100, "status": "Error in connection database"}); return; } connection.query('select Id, Name, Password from Users ' + 'where Users.Name = ?', [username], function (err, rows) { connection.release(); if (!err) { return rows; } else { return false; } }); //connection.on('error', function (err) { // res.send({"code": 100, "status": "Error in connection database"}); // return; //}); }); } } module.exports = new Login();
我得到的输出是:
Server listening on port 3000 Something is happening error handler second Connection
所以我想知道这个代码是双重的:
- 为什么第一个承诺不会在继续if / else之前等待
findUser
返回,那么为了发生这种情况我需要做些什么? - 为什么
error handler second
输出,但没有Failed
?
我觉得有什么我完全误解了承诺。 我很感激任何答案。 谢谢。
与代码有关的问题
好的,这里有很多问题,所以首先要做的事情。
connection.query('...', function (err, rows) { connection.release(); if (!err) { return rows; } else { return false; } });
这是行不通的,因为你正在向调用者返回数据,调用者是用err
和rows
调用你的callback的数据库查询,并且不关心你的callback的返回值。
你需要做的是当你有行或者你没有时调用其他函数或方法。
你在打电话:
var rows = loginM.findUser(req.body, res);
你希望得到那里的行,但你不会。 你会得到什么是undefined
,你会得到它比数据库查询甚至开始更快。 它是这样工作的:
me.findUser = function(params, res) { // (1) you save the username in a variable var username = params.username; // (2) you pass a function to getConnection method pool.getConnection(function (err, connection) { console.log("Connection "); if (err) { console.log("ERROR 1 "); res.send({"code": 100, "status": "Error in connection database"}); return; } connection.query('select Id, Name, Password from Users ' + 'where Users.Name = ?', [username], function (err, rows) { connection.release(); if (!err) { return rows; } else { return false; } }); //connection.on('error', function (err) { // res.send({"code": 100, "status": "Error in connection database"}); // return; //}); }); // (3) you end a function and implicitly return undefined }
在连接到数据库之前,在传递函数之后, pool.getConnection
方法会立即返回。 然后,在一段时间之后,您传递给该方法的函数可能会被调用,但在已经将undefined
的代码返回给需要值的代码之后,
var rows = loginM.findUser(req.body, res);
而不是从callback中返回值,你需要调用一些其他的函数或方法(如一些你需要调用的callback函数或者一个解决承诺的方法)。
返回值是一个同步的概念,不适用于asynchronous代码。
如何承诺应该使用
现在,如果你的函数返回了一个promise :
me.findUser = function(params, res) { var username = params.username; return new Promise(function (res, rej) { pool.getConnection(function (err, connection) { console.log("Connection "); if (err) { rej('db error'); } else { connection.query('...', [username], function (err, rows) { connection.release(); if (!err) { res(rows); } else { rej('other error'); } }); }); }); }
那么你就可以像这样在代码的其他部分使用它:
app.post('/login/', function(req, res, next) { var promise = new Promise(function (resolve, reject) { // rows is a promise now: var rows = loginM.findUser(req.body, res); rows.then(function (rowsValue) { console.log("Success"); resolve(rowsValue); }).catch(function (err) { console.log("Failed"); reject(err); }); }); // ...
说明
总之,如果你正在运行一个asynchronous操作 – 就像数据库查询 – 那么你不能立即得到这样的值:
var value = query();
因为服务器在执行任务之前需要阻止等待数据库 – 这就是每种语言在同步,阻塞I / O时发生的情况(这就是为什么你需要在这些语言中有线程,以便其他的东西可以该线程被阻止时完成)。
在Node中,您可以使用传递给asynchronous函数的callback函数,以便在有数据时调用它:
query(function (error, data) { if (error) { // we have error } else { // we have data } }); otherCode();
或者你可以得到一个承诺:
var promise = query(); promise.then(function (data) { // we have data }).catch(function (error) { // we have error }); otherCode();
但是在这两种情况下,在注册callbackotherCode()
或promise处理程序之后,在查询有数据之前, otherCode()
将立即运行 – 这是不需要阻塞的。
概要
整个想法是,在像Node.JS这样的asynchronous,非阻塞,单线程的环境中,你一次只能做一件事 – 但是你可以等待很多事情。 但是,当你在等待的时候,你不只是等待什么,什么都不做,你安排了其他的事情,等待更多的事情,最终在你准备好的时候你会被打回去。
其实我写了一个关于中等的短篇故事来说明这个概念: 在这个星球上的非黑化I / O Asynchronia256 / 16 – 一个松散的基于不确定事实的短小故事 。