Node.js'de next () ne zaman kullanılır ve next () ne zaman dönülür?


136

Senaryo : Aşağıdakinin bir düğüm web uygulamasındaki kodun parçası olduğunu düşünün.

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

Sorun : Hangisinin sadece next()veya ile gideceğini kontrol ediyorum return next(). Yukarıdaki örnek kod her ikisi için de tamamen aynı şekilde çalışır ve yürütmede herhangi bir farklılık göstermez.

Soru : Biri buna ışık tutabilir mi, ne zaman next()ve ne zaman kullanılmalı return next()ve bazı önemli farklar?

Yanıtlar:


141

Bazı insanlar her zaman return next()geri aramayı tetikledikten sonra yürütmenin durmasını sağlamak için yazarlar .

Bunu yapmazsanız, geri aramayı ikinci kez tetikleme riskiyle karşılaşırsınız ve bu genellikle yıkıcı sonuçlar doğurur. Kodunuz olduğu gibi iyi, ancak şu şekilde yeniden yazarım:

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

    if(!id)
        return next();

    // do something
});

Bana bir girinti seviyesi kazandırıyor ve kodu daha sonra tekrar okuduğumda, nextiki kez çağrılmanın bir yolu olmadığından eminim .


2
Bu tür bir duruma res.redirect('/')karşı benzer bir şey doğru return res.redirect('/')olur mu? Belki de, gönderildikten sonra başlık ayarlama hatalarını önlemek için her zaman res ifadelerinin önüne return yazmak daha iyidir?
Adam D

187

@Laurent Perrin'in cevabı olarak:

Bunu yapmazsanız, geri aramayı ikinci kez tetikleme riskiyle karşılaşırsınız ve bu genellikle yıkıcı sonuçlar doğurur

Böyle bir ara yazılım yazarsanız burada bir örnek vereceğim:

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()
})

Konsoldaki çıktının şöyle olduğunu göreceksiniz:

This is a middleware
This is second middleware
This is third middleware
This is first-half middleware

Yani, tüm ara yazılım işlevi bittikten sonra next () 'nin altındaki kodu çalıştırır.

Ancak, kullanırsanız return next(), geri aramayı hemen atlayacak ve geri aramada aşağıdaki koda return next()ulaşılamayacaktır.


29
expressBu cevaba yeni başlayan biri olarak , her şeyi diğer cevaplardan daha açık hale getirdi. Başparmak havaya!
mandarin

1
Bu tür bir duruma res.redirect('/')karşı benzer bir şey doğru return res.redirect('/')olur mu? Belki de , gönderildikten sonra başlık ayarlama hatalarından kaçınmak için her zaman ifadelerin returnönüne yazmak daha iyidir res?
Adam D

1
Neden sonraki () 'den sonra kod yazmalıyım? Bir ara katman yazılımında görevimi bitirdikten sonra hiçbir şey yapmadığım açık değil mi? @PJCHENder
Imran Pollob

1
@ImranPollob bazen hatalar olur. Çok fazla kod yazdığınızda, ifs / elses / etc. `` Sonraki dönüş () '' unutabilirsiniz
Jone Polvora

46

next()connect ara yazılımının bir parçasıdır . Yönlendirici akışı için geri aramalar, işlevlerinizden bir şey döndürüp döndürmediğinizi önemsemez, bu nedenle return next()ve next(); return;temelde aynıdır.

İşlevlerin akışını durdurmak istemeniz durumunda next(err)aşağıdaki gibi kullanabilirsiniz

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()İsteklerinizin ara katman yazılımını genişletmek için oldukça fazla kullanılır.


1
Aşağıdaki gibi parametreler gönderebilir miyiz next('No ID')?
Amol M Kulkarni

7
next('No ID')aslında akışı kesecek bir hata gönderiyor.
drinchev

Next (null, "somevalue"); Async.waterfall gibi araçlar için değeri bir sonraki işleve aktarır. Veri odaklı karmaşık etkileşimler dizisi için genellikle işlevler arasında bir bağlam nesnesi geçiririm. Bu şekilde, birden çok uç noktada paylaşılabilen ve bağlamdaki veriler aracılığıyla akışı kontrol edebilen genel işlevler oluşturabilirim
Chad Wilson

5
"bu yüzden next () ve next (); return; temelde aynıdır." - tam da okumam gerekenler. thx @drinchev
Nick Pineda

1
Tersini gözlemliyorum (hata ateşlerken): next (hata) sonraki ara yazılımı tetikler, ancak kodu çalıştırmaya devam eder; sonraki dönüş (hata) yalnızca yürütmeyi bir sonraki ara katman yazılımına aktarır. next (e) ve return next (e) aynı DEĞİLDİR.
Nickolodeon

0

Hiç kullanmamak en iyisidir! Açıklıyorum ve bunu da açıklıyorum.

Herhangi bir ada sahip olabilen next () işlevi, bir sonraki olarak ayarlanmıştır. Örneğin, genellikle aynı URI kaynağı üzerinde gerçekleştirilen işlemlerle (PUT, GET, DELETE, ...) dolaylı olarak ilgilidir./ 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 ()...)

Şimdi app.get, app.put ve app.delete öğelerine bakarsanız aynı uri'yi (/ user /: id) kullanırsanız, onları ayıran tek şey bunların uygulanmasıdır. İstek yapıldığında (req) express, req'i app.get içinde ilk sıraya koyar, bu istek söz konusu denetleyici için olmadığı için oluşturduğunuz herhangi bir doğrulama başarısız olursa, req'i te dosyasında bir sonraki yol olan app.put'a iletir ve böylece üzerinde. Aşağıdaki örnekte görüldüğü gibi.

    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()

   })

Sorun şu ki, sonunda isteğin doğrulanması yoluyla istediğiniz şeyi yapan bir tane olmasını ümit ederek tüm denetleyicilere isteği iletiyorsunuz. Sonunda, tüm kontrolörler kendileri için olmayan bir şeyi alırlar :(.

Peki next () sorunundan nasıl kaçınılır ?

Cevap gerçekten çok basit.

1- Bir kaynağı tanımlamak için yalnızca bir uri olmalıdır

http: // IpServidor / colection /: resource / colection /: resource eğer URI'niz bundan daha uzunsa, yeni bir uri oluşturmayı düşünmelisiniz

Örnek http: // IpServidor / users / pepe / contact / contacto1

2-Bu kaynak üzerindeki tüm işlemler http (get, post, put, delete, ...) fiillerinin idempotansına göre yapılmalıdır, bu nedenle bir URI'ye yapılan çağrının gerçekten sadece bir arama yolu vardır

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

Daha fazla bilgi [ https://docs.microsoft.com/es-es/azure/architecture/best-practices/api-design#organize-the-api-around-resources][1]

Kodu görelim! Next () kullanımından kaçınmamızı sağlayan somut uygulama!

İndex.js dosyasında

//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 dosyasında

    //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;

Artık usersRoute.js dosyası, usersRoute adlı bir dosyanın yapması beklenen şeyi yapar, bu da URI / users /

// getUsersController.js dosyası

//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;

Bu şekilde bir sonraki kullanımdan kaçınırsınız, kodu ayırırsınız, performans kazanırsınız, SOLID geliştirirsiniz, mikro hizmetlere olası bir geçiş için kapıyı açık bırakırsınız ve her şeyden önce bir programcı tarafından okunması kolaydır.


2
Bu yanlıştır, app.get önerdiğiniz gibi app.put'a geçmeyecektir. Yalnızca eşleşen istekler çağrılır, bu nedenle yöntem GET ise yalnızca app.get ara yazılımı çağrılır. Ara yazılımın istek yöntemini kontrol etmesi gerekmez. Öneriniz, birincil bir ifade işlevini yok sayar ve bunun yerine kendi yönlendirmenizi uygular. Dahası, öneriniz rotanızın, hiçbir yerden geçemeyeceği için kullanacağınız tek ara yazılım olduğunu varsayar.
Ravenex

Yanlış bilgi, lütfen yukarıdaki cevaplara bakınız.
DDiamond

-3

Sonraki() :

Bu işlevi çağırmak, uygulamadaki bir sonraki ara yazılım işlevini çağırır. Next () işlevi, Node.js veya Express API'nin bir parçası değildir, ancak ara yazılım işlevine iletilen üçüncü bağımsız değişkendir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.