La natura dei callback in Node.js

6

Nel mondo javaScript semplice ho imparato che le funzioni annidate possono essere problematiche perché la funzione interna viene "ricreata" ogni volta che viene chiamata la funzione esterna:

function outer(a) {
    function inner(arg1,arg2){
        return arg1 + arg2;
    }
    return inner(a, 6);
}
myVar = outer(4);

Apparentemente la funzione interna è spazzatura e la costante ri-creazione di essa ha un costo sulle prestazioni. Questo potrebbe essere rielaborato come:

function inner(arg1, arg2) {
    return arg1 + arg2;
}

function outer(a) {
    return inner(a, 6);
}

myVar = outer(4);

Se ho ragione, sembra che il compromesso risieda nel mutevole ambito dell'intimo; il fatto che la funzione interiore non ha più accesso alle proprie variabili esterne. Se sono corretto finora, passiamo a Node.JS. Il nodo è pesante sui callback e la mia domanda è: le funzioni di callback asincrone tipiche del nodo vengono anche "ricreate" ogni volta che vengono attivate? Prendi il seguente costrutto del nodo comune:

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');

In realtà la funzione può diventare piuttosto grande; può comprendere molte funzionalità. La richiamata sopra è "ricreata" ogni volta che un client OTTIENE o POST il server? In tal caso, sarebbe meglio disaccoppiare sempre i callback come nell'esempio javaScript normale:

function handleGET(req, res) {
   res.writeHead(200, {'Content-Type': 'text/plain'});
   res.end('Hello World\n');
}

http.createServer(handleGET).listen(1337, '127.0.0.1');

come domanda bonus correlata, anche le funzioni degli eventi vengono ricreate? Trarrebbero beneficio dalla dichiarazione precedente?

myObj.on('someEvent', function someFunction() {...});

vs.

function someFunction() {...}
myObj.on('someEvent', someFunction);
    
posta Dave 10.08.2014 - 03:32
fonte

3 risposte

4
http.createServer(function (req, res)
{
    // do stuff
});

è quasi esattamente lo stesso di

function handler (req, res)
{
    // do stuff
}

http.createServer(handler);

Gli argomenti passati a una funzione chiamata vengono valutati nello stesso ambito della chiamata. Ora, se avessi fatto qualcosa del tipo:

http.createServer(function (req, res)
{ 
  function handler (req, res)
  {
    // do stuff
  }
  return handler(req, res);
});

Quindi sì, dovresti creare una nuova funzione per ogni richiesta, e ciò sarebbe inefficiente. In termini di qualcosa come un server web questo di solito non è un problema poiché i gestori delle richieste sono spesso dichiarati in un unico posto.

L'unica volta che vuoi veramente nidificare le funzioni (che è molto diverso dal passare una funzione come argomento, come si fa nei tuoi esempi), è quando hai bisogno di riferimenti alle variabili dell'enclosure che racchiudono (es .: a chiusura)

In risposta alla tua seconda domanda, no. Non c'è nulla di diverso nelle funzioni del gestore di eventi, ed entrambi gli esempi sono funzionalmente equivalenti e dovrebbero essenzialmente compilare lo stesso codice macchina.

    
risposta data 10.08.2014 - 22:16
fonte
8

Node.JS non cambia fondamentalmente il modo in cui funziona JavaScript, e il problema che stai descrivendo è un problema di Javascript.

Più specificamente, poiché la funzione interiore è all'interno dell'ambito di una funzione esterna, viene ricreata ogni volta che la funzione interna entra e lascia l'ambito esterno. È esattamente la stessa cosa che accade quando dichiari una variabile all'interno di una funzione, invece che all'esterno di essa. Node.JS non ha nulla da dire su tutto ciò.

Fondamentalmente, le funzioni di callback sono solo funzioni ; non hanno alcuna proprietà speciale che modifica il loro modo di comportarsi nell'ambito locale.

Related
Errore JSlint "Non creare funzioni all'interno di un ciclo".

    
risposta data 10.08.2014 - 05:30
fonte
1

Si noti che una moderna implementazione JavaScript creerà solo oggetti funzione per istanze diverse della stessa funzione, questi oggetti possono facilmente condividere il codice.

Entrambi i tuoi primi due esempi dovrebbero, almeno in V8, avere la funzione interna delineata dall'ottimizzatore, rimuovendo così in modo efficace il sovraccarico di avere una seconda funzione. Cercherò di trovare il tempo per alcuni benchmark, ma per ora prendo atto che il primo esempio potrebbe potenzialmente essere più veloce perché può essere verificato con una semplice analisi statica che la funzione interna non cambierà mai. Il secondo esempio deve essere in grado di gestire la possibilità che la variabile globale inner cambi valore.

Fornisci il codice di esempio:

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');

Si noti che questo non è un esempio di più istanze della stessa funzione, createServer è chiamato una volta ed è in questo processo data l'unica istanza della funzione anonima che sia mai stata creata. È probabile che chiami la funzione anonima più volte, ma questa è una questione diversa.

    
risposta data 12.08.2014 - 22:20
fonte

Leggi altre domande sui tag