Me pregunto cómo podemos usar res.render dentro de una devolución de llamada
function getUsers(cb){ fs.readFile('data.json', 'utf8', (err, data) => { if (err) return cb(err); const users = JSON.parse(data); return cb(null, users); }); } app.get('/', (req,res) => { getUsers((err,users) =>{ if(err){ res.render('error', {error:err}) } else{ res.render('index', {title: "users", users: users.users}); } }) });Porque cuando pasamos la devolución de llamada, Callstack se carga con la función getUsers (cb), y ya no estamos dentro de la ruta, entonces, ¿cómo la devolución de llamada está usando el método res.render? ¿Y cómo sé en el futuro, qué valores son accesibles para las devoluciones de llamada?
Las funciones/devoluciones de llamada en línea como las que está usando aquí pueden ver el alcance de la función principal y todas sus variables y argumentos. Esto se conoce como el "alcance léxico".
Si la devolución de llamada no estaba en línea, entonces no podía ver esas variables/argumentos porque la función se declararía en un ámbito diferente.
Entonces, esta es la razón por la que la devolución de llamada en línea para readFile() que ha declarado puede acceder a cb(...) y, de manera similar, la devolución de llamada en línea que pasa a getUsers() puede acceder a req y res . Esos son todos los argumentos en el ámbito principal.
Tenga en cuenta que el acceso a estas variables/argumentos principales no se realiza desde la pila de llamadas. Esto es del ámbito léxico .
Este acceso a res.render() solo funciona porque la función se declara dentro del ámbito léxico donde se puede acceder a res . Si su ruta fue declarada así en su lugar:
function getUsersCallback(err, users) { if(err){ res.render('error', {error:err}) } else{ res.render('index', {title: "users", users: users.users}); } } app.get('/', (req,res) => { getUsers(getUsersCallback); }); Entonces esto no funcionaría porque la función de devolución de llamada no está declarada en un ámbito léxico que tiene acceso a req y res .
Tenga en cuenta que los argumentos de función y las variables locales en Javascript se almacenan en objetos de alcance, no en la pila de llamadas como lo estarían en un lenguaje como C/C++. Esto se debe a un montón de razones, una de las cuales es que la vida útil del alcance de una función puede extenderse más allá de cuando la función regresa (debido a los cierres) y para que los alcances se puedan encadenar para que el intérprete pueda buscar cosas en el alcance principal ( para implementar el "ámbito léxico" que implementa el lenguaje).