我正在尝试使用NodeJS构建登录API,但是我的代码没有达到我的期望。我对js,promise和其他所有语言都是新手,因此请尽可能简化任何答案。
从我的代码输出中可以看到,第一个promise部分不会等到函数findUsers(...)完成。
findUsers(...)
我有一个路由文件,我要在其中依次运行一些功能:
路由文件现在包含:
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函数包含池化和查询,并位于模型文件中:
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
因此,我想了解这段代码是双重的:
error handler second
Failed
我觉得我对诺言完全有些误解。感谢您的回答。谢谢。
好的,这里有很多问题,所以首先要先做。
connection.query('...', function (err, rows) { connection.release(); if (!err) { return rows; } else { return false; } });
这将无法正常工作,因为您正在将数据返回给调用方,这是使用err和调用回调rows并且不关心回调的返回值的数据库查询。
err
rows
您需要做的是在有行或无行时调用其他函数或方法。
您正在致电:
var rows = loginM.findUser(req.body, res);
并且您希望在那里获得行,但不会。您将获得的是undefined,甚至比启动数据库查询还要快。它是这样的:
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到需要以下值的代码很久之后:
pool.getConnection
与从回调中返回值不同,您需要从它们中调用其他一些函数或方法(例如您需要调用的某些回调或用于解决Promise的方法)。
返回值是一个同步概念,不适用于异步代码。
现在,如果您的函数返回了 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); }); }); // ...
总而言之,如果您正在运行异步操作(例如数据库查询),则无法立即获得如下所示的值:
var value = query();
因为服务器需要先阻塞等待数据库才能执行分配-这就是在每种语言中都发生同步阻塞I / O的情况(这就是为什么您需要使用这些语言的线程以便可以做其他事情)在该线程被阻止时完成)。
在Node中,您可以使用传递给异步函数的回调函数来在有数据时进行调用:
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();
但是在这两种情况下,otherCode()将在注册您的回调或promise处理程序后立即运行,而不需要查询包含任何数据,这无需执行阻止操作。
otherCode()
整个想法是,在像Node.JS这样的异步,无阻塞,单线程环境中,您一次不会做一件事情,但是您可以等待很多事情。但是,您不只是等待某事而在等待时什么也不做,您安排其他事情,等待更多事情,最终在准备就绪时会给您回电。
实际上,我在Medium上写了一个简短的故事来说明这个概念:在Asynchronia256 / 16星球上避免I / O变黑- 基于不确定的事实,一个松散的简短故事。