Javascript Node.js是否阻止事件循环?
我正在编写一个API,我陷入了根据传入请求混合异步和同步代码的困境,请看下面的示例 routes.jsJavascript Node.js是否阻止事件循环?,javascript,node.js,Javascript,Node.js,我正在编写一个API,我陷入了根据传入请求混合异步和同步代码的困境,请看下面的示例 routes.js module.exports = [ { method: 'GET', path: '/', controller: 'main', action: 'main', description: 'lists the API functionality', access: 'auth'
module.exports = [
{
method: 'GET',
path: '/',
controller: 'main',
action: 'main',
description: 'lists the API functionality',
access: 'auth'
},
{
method: 'POST',
path: '/users',
controller: 'users',
action: 'create',
description: 'creates a new user',
fields: {
fullName: {
format: {
min: 2,
max: 64,
minWords: 2,
disableDoubleSpaces: true
},
description: 'the full name of the new user',
examples: 'Thomas Richards, Richard Jones, Michael J. Fox, Mike Vercoelen, John Johnson'
},
email: {
format: {
min: 2,
max: 64,
maxWords: 1,
match: 'email'
},
description: 'the email address of the new user',
examples: 'mike@grubt.com, lilly@gmail.com, thomas.richards@mail.com, peter@mymail.com'
},
password: {
format: {
min: 2,
max: 64
},
description: 'the password of the new user',
examples: '123abcdfg, 7373kEjQjd, #8klKDNfk'
}
}
}
];
var http = require('http');
var url = require('url');
var os = require('os');
var dns = require('dns');
var apiServer = module.exports;
var routes = require('./routes.js'); // Routes file from above.
var req, res, controller, action, serverInfo, httpServer;
apiServer.start = function(){
prepare(function(){
httpServer = http.createServer(handleRequest).listen(3000);
});
};
//
// We need to do this function, we need the local ip address of the
// server. We use this local ip address in logs (mongoDb) so we can
// refer to the correct server.
//
function prepare(callback){
var serverName = os.hostname();
dns.lookup(serverName, function(error, address){
if(error){
throw error;
}
serverInfo = {
name: serverName,
address: address
};
callback();
});
}
function getRoute(){
// loops through routes array, and picks the correct one...
}
function getAuth(callback){
// parses headers, async authentication (mongoDB).
}
function getRequestData(callback){
// req.on('data') and req.on('end'), getting request data.
}
function parseRequestData(callback){
// parse request data at this point.
}
function validateRequestData(callback){
// loop through route fields (see routes.js) and validate this data with the ones
// from the request.
}
function requireControllerAndCallAction(){
// do actual job.
}
function handleRequest(request, response){
req = request;
res = response;
req.route = getRoute(); // First step for a request, syncronous.
if(req.route === false){
// 404...
}
// If in the routing schema access was "auth",
// this route requires authentication, so do that...
if(req.route.access === 'auth'){
getAuth(function(error, user){
if(error){ // 401 } else {
req.user = user;
}
}
}
if(req.method === 'POST' || req.method === 'PUT'){
// Async functions.
getRequestData(function(){
parseRequestData(function(){
validateRequestData(function(){
requireControllerAndCallAction();
});
});
});
} else {
requireControllerAndCallAction();
}
}
js文件基本上是API的一个非常重要的部分,它验证传入的数据,路由到正确的控制器/操作,并定义方法是公共的,还是需要身份验证(基本身份验证)
api server.js
module.exports = [
{
method: 'GET',
path: '/',
controller: 'main',
action: 'main',
description: 'lists the API functionality',
access: 'auth'
},
{
method: 'POST',
path: '/users',
controller: 'users',
action: 'create',
description: 'creates a new user',
fields: {
fullName: {
format: {
min: 2,
max: 64,
minWords: 2,
disableDoubleSpaces: true
},
description: 'the full name of the new user',
examples: 'Thomas Richards, Richard Jones, Michael J. Fox, Mike Vercoelen, John Johnson'
},
email: {
format: {
min: 2,
max: 64,
maxWords: 1,
match: 'email'
},
description: 'the email address of the new user',
examples: 'mike@grubt.com, lilly@gmail.com, thomas.richards@mail.com, peter@mymail.com'
},
password: {
format: {
min: 2,
max: 64
},
description: 'the password of the new user',
examples: '123abcdfg, 7373kEjQjd, #8klKDNfk'
}
}
}
];
var http = require('http');
var url = require('url');
var os = require('os');
var dns = require('dns');
var apiServer = module.exports;
var routes = require('./routes.js'); // Routes file from above.
var req, res, controller, action, serverInfo, httpServer;
apiServer.start = function(){
prepare(function(){
httpServer = http.createServer(handleRequest).listen(3000);
});
};
//
// We need to do this function, we need the local ip address of the
// server. We use this local ip address in logs (mongoDb) so we can
// refer to the correct server.
//
function prepare(callback){
var serverName = os.hostname();
dns.lookup(serverName, function(error, address){
if(error){
throw error;
}
serverInfo = {
name: serverName,
address: address
};
callback();
});
}
function getRoute(){
// loops through routes array, and picks the correct one...
}
function getAuth(callback){
// parses headers, async authentication (mongoDB).
}
function getRequestData(callback){
// req.on('data') and req.on('end'), getting request data.
}
function parseRequestData(callback){
// parse request data at this point.
}
function validateRequestData(callback){
// loop through route fields (see routes.js) and validate this data with the ones
// from the request.
}
function requireControllerAndCallAction(){
// do actual job.
}
function handleRequest(request, response){
req = request;
res = response;
req.route = getRoute(); // First step for a request, syncronous.
if(req.route === false){
// 404...
}
// If in the routing schema access was "auth",
// this route requires authentication, so do that...
if(req.route.access === 'auth'){
getAuth(function(error, user){
if(error){ // 401 } else {
req.user = user;
}
}
}
if(req.method === 'POST' || req.method === 'PUT'){
// Async functions.
getRequestData(function(){
parseRequestData(function(){
validateRequestData(function(){
requireControllerAndCallAction();
});
});
});
} else {
requireControllerAndCallAction();
}
}
如您所见,有些函数是异步的(getAuth、getRequestData),有些函数是同步的(parseRequestData、validateRequestData)
现在事情是这样的:
请求1。随方法POST、url'/users'和数据一起提供:
- 全名='Rick'
- 电邮:"瑞克"
- 密码:“a”
现在让我们想象一下,数据的验证需要5秒钟(这是延迟的,但只是举个例子),在验证过程中,一个新的请求进来,新的请求在前一个请求完成之前不会被处理,对吗?如果它们是同步的,如果它们确实需要5秒钟,那么是的,对于该服务器实例,请求将被阻止。这就是为什么阻塞调用(网络、数据库、文件系统等)是异步的非常重要。事件循环必须保持循环或整个服务器阻塞 这篇文章的一个要点是: …但是,除了您的代码之外,所有内容都并行运行 这意味着昂贵的I/O应该是异步的,但您的代码可能会阻塞。但是,我们担心在服务器上阻塞的I/O通常非常昂贵 “您的代码”通常只是处理来自长时间运行的I/O调用的回调,更新您的状态,然后触发另一个调用。但这就是它的美妙之处——当您更新状态时,它位于主事件循环中,因此不需要多线程访问“您的”状态和代码。没有锁,没有死锁等。。。但是异步和并行I/O的所有好处都是昂贵的 另一个关键点(5秒的非IO工作将涉及到这一点)是: 除了I/O调用,Node.js希望所有请求都返回 迅速地;e、 g.CPU密集型工作应分为其他工作 您可以与事件交互或使用 像WebWorkers这样的抽象
此外,是否希望“auth”和“POST”|“PUT”在同一请求中发生?如果是这样,您可能会有问题。getAuth看起来是异步的,但随后立即转到req.method检查。到那时,getAuth仍然可以工作。如果您希望POST和PUT经过身份验证,那么该异步方法块可能需要使用getAuth async方法进行包装。OK谢谢您的回答,有没有一种方法可以在不同的线程/核心上处理验证(通过集群/子进程),这将非常棒,验证不会阻止任何东西。只需使验证和请求路径中的所有调用异步即可。您也不能使单个请求在节点中的多个核心上工作,因为事件循环在一个核心的一个线程上。但是,您可以做的是创建多个node实例以获得多核并行性。有这样的解决方案:我如何使验证和所有这些调用异步,然后,不知何故,我循环通过数据,并验证它,我的意思是没有办法使它异步对吗?我编辑了这篇文章。一个关键的概念是“……然而,除了代码之外,所有东西都是并行运行的”还请注意非IO/CPU密集型工作的一点,5秒的验证可能会。。。