何时使用next()并在Node.js中返回next()

时间:2013-05-29 09:39:16

标签: node.js express connect v8

场景:请考虑以下是节点网络应用程序的代码部分。

app.get('/users/:id?', function(req, res, next){
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next(); //or return next();
    }
});

问题:我正在检查哪一个只有next()return next()。以上示例代码对于&没有表现出任何执行上的差异。

问题:有人可以说明这一点,何时使用next()以及何时使用return next()和一些重要区别?

6 个答案:

答案 0 :(得分:106)

有些人总是写return next()是为了确保在触发回调后执行停止。

如果你不这样做,你可能会在第二次触发回调,这通常会产生毁灭性的结果。你的代码很好,但我会把它重写为:

app.get('/users/:id?', function(req, res, next){
    var id = req.params.id;

    if(!id)
        return next();

    // do something
});

它为我节省了缩进级别,当我稍后再次阅读代码时,我确信无法再调用next两次。

答案 1 :(得分:104)

作为@Laurent Perrin的回答:

  

如果你不这样做,你可能会在第二次触发回调,这通常会带来毁灭性的结果

如果你写这样的中间件,我在这里给出一个例子:

InstrumentType

您会发现控制台中的输出是:

app.use((req, res, next) => {
  console.log('This is a middleware')
  next()
  console.log('This is first-half middleware')
})

app.use((req, res, next) => {
  console.log('This is second middleware')
  next()
})

app.use((req, res, next) => {
  console.log('This is third middleware')
  next()
})

也就是说,它在所有中间件函数完成后运行next()下面的代码。

但是,如果您使用This is a middleware This is second middleware This is third middleware This is first-half middleware ,它会立即跳出回调,并且回调中的return next()下面的代码将无法访问。

答案 2 :(得分:42)

next()connect middleware的一部分。如果您从函数中返回任何内容,路由器流程的回调并不在意,因此return next()next(); return;基本相同。

如果您想要停止功能流,可以使用next(err),如下所示

app.get('/user/:id?', 
    function(req, res, next) { 
        console.log('function one');
        if ( !req.params.id ) 
            next('No ID'); // This will return error
        else   
            next(); // This will continue to function 2
    },
    function(req, res) { 
        console.log('function two'); 
    }
);

非常next()用于扩展请求的中间件。

答案 3 :(得分:2)

next() 和 return next() 的区别很简单,作为另一个编程原则。部分代码解释如下:


app.use((req, res, next) => {
   console.log('Calling first middleware');
   next();
   console.log('Calling after the next() function');
});


app.use((req, res, next) => {
   console.log('Calling second middleware');
   return next(); // It returns the function block immediately and call next() function so the return next(); and next(); return; are the same
   console.log('After calling return next()');
});
// Output is Calling first middleware Calling after the next() function Calling second middleware

答案 4 :(得分:1)

最好根本不使用它!我解释了,这也是我的解释。

根据约定,可以具有任何名称的next()函数已设置为next。它与通常在同一URI资源上执行的操作(PUT,GET,DELETE等)间接相关,例如/ user /: id

app.get('/user/:id', function (req,res,next)...)
app.put('/user/:id', function (req,res,next)...)
app.delete('/user/:id', function (req,res,next)...)
app.post('/user/', function ()...)

现在,如果您查看app.get,app.put和app.delete使用相同的uri(/ user /:id),则区别它们的唯一方面就是它们的实现。发出请求(req)Express时,将req放在app.get中的首位,如果由于该请求不是针对该控制器的请求而创建的验证失败,则会将req传递到app.put,这是te文件中的下一条路由,因此上。如下面的示例所示。

    app.get('/user/:id', function (req,res,next){

    if(req.method === 'GET')
    //whatever you are going to do
    else
      return next() //it passes the request to app.put

    //Where would GET response 404 go, here? or in the next one. 
    // Will the GET answer be handled by a PUT? Something is wrong here.

   })
    app.put('/user/:id', function (req,res,next){

    if(req.method === 'PUT')
    //whatever you are going to do
    else
      return next()

   })

问题在于,最终您最终需要将req传递给所有控制器,以希望有一个控制器可以通过req的验证来完成您想要的操作。最后,所有控制器最终都会收到不适合他们的东西:(。

那么,如何避免next()问题?

答案很简单。

1- 只能有一个uri 来标识资源

http://IpServidor/colection/:resource/colection/:resource,如果您的URI超出此长度,则应考虑创建新的uri

示例http://IpServidor/users/pepe/contacts/contacto1

2-必须对此资源进行所有操作,以遵守动词http(获取,发布,放置,删除,...)的幂等性,因此对URI的调用实际上只有一种调用方式

POST http://IpServidor/users/  //create a pepe user 
GET http://IpServidor/users/pepe  //user pepe returns   
PUT http://IpServidor/users/pepe  //update the user pepe 
DELETE http://IpServidor/users/pepe  //remove the user pepe

更多信息[https://docs.microsoft.com/es-es/azure/architecture/best-practices/api-design#organize-the-api-around-resources][1]

让我们看一下代码!使我们避免使用next()的具体实现!

在文件index.js中

//index.js the entry point to the application also caller app.js
const express = require('express');
const app = express();

const usersRoute = require('./src/route/usersRoute.js');

app.use('/users', usersRoute );

在usersRoute.js文件中

    //usersRoute.js
    const express = require('express');
    const router = express.Router();

    const getUsersController = require('../Controllers/getUsersController.js');
    const deleteUsersController = require('../Controllers/deleteUsersController.js');

    router.use('/:name', function (req, res) //The path is in /users/:name
    {
    switch (req.method)
    {
    case 'DELETE':
      deleteUsersController(req, res);
      break;
    case 'PUT':
     // call to putUsersController(req, res);
     break;
    case 'GET':
     getUsersController(req, res);
     break;
    default:
     res.status(400).send('Bad request');
    } });

router.post('/',function (req,res) //The path is in /users/
{
    postUsersController(req, res);
});

module.exports = router;

现在,usersRoute.js文件可以执行名为usersRoute的文件,该文件将管理URI / users /

的路由。

//文件getUsersController.js

//getUsersController.js
    const findUser= require('../Aplication/findUser.js');
    const usersRepository = require('../Infraestructure/usersRepository.js');

    const getUsersController = async function (req, res)
    {

       try{
          const userName = req.params.name;
        //...
          res.status(200).send(user.propertys())

        }catch(findUserError){
           res.status(findUserError.code).send(findUserError.message)
        }
    }
   module.exports = getUsersController;

通过这种方式,您可以避免使用next程序,将代码解耦,提高性能,开发SOLID,为可能迁移到微服务打开大门,并且最重要的是,程序员易于阅读

答案 5 :(得分:0)

Next():

  

调用此函数将调用应用程序中的下一个中间件函数。   next()函数不是Node.js或Express API的一部分,但是   是传递给中间件功能的第三个参数。