‫Jonas: Escribamos ahora algo
‫de código para comprender mejor lo que
‫sucede en el bucle de eventos.
‫Así que, al igual que antes,
‫para comenzar con la parte de codificación
‫de esta sección, siga adelante y obtenga
‫los archivos de inicio para esta sección, cópielos en
‫algún lugar y luego abra el proyecto en su editor de código.
‫Así que lo tengo aquí en el escritorio
‫y en mi VSCode, y todo lo que tenemos aquí para
‫comenzar es este archivo de prueba. txt, por lo que crearé un nuevo archivo
‫aquí, y lo llamaré bucle de eventos. js.
‫Muy bien, ahora es extremadamente difícil simular el bucle de eventos
‫correctamente, porque realmente no podemos poner muchas
‫devoluciones de llamada en todas las colas
‫de devolución de llamada
‫de las que hablamos antes, todas al mismo tiempo, ¿verdad?
‫Esa situación ocurre cuando, por ejemplo,
‫ingresan muchas solicitudes a su aplicación, pero
‫aquí de manera local, eso es muy difícil de replicar.
‫Pero de todos modos, todavía haremos algunos experimentos muy
‫interesantes usando algunas de las cosas que
‫aprendimos en el último video.
‫Y lo que vamos a hacer
‫es escribir un montón de líneas de
‫código y luego tratar de averiguar en qué orden
‫deben ejecutarse en el ciclo de eventos y analizar
‫si los resultados que obtenemos realmente tienen sentido.
‫Así que comencemos escribiendo un setTimeout, básicamente
‫para configurar un temporizador, y estoy usando
‫una función de flecha aquí,
‫y lo único
‫que voy a hacer es iniciar sesión en
‫la consola con una cadena, así que consola. log, el temporizador uno terminó
‫y quiero que expire justo después de cero segundos.
‫Bien, guarde, y luego verá que realmente
‫corrigió esta cadena aquí, por lo que
‫cambió estas comillas y agregó el punto y coma, y
‫eso se debe a
‫la extensión Prettier que instalamos antes.
‫Ahora no lo voy a configurar
‫aquí, porque para este
‫pequeño ejemplo, eso no es realmente necesario, está bien.
‫Eso es configurar un temporizador, entonces
‫también usemos setImmediate, así que recuerde eso del último video.
‫Bien, ahora no voy a explicar mucho aquí,
‫por ahora escribamos este código
‫y luego analicemos lo que sucede, está bien.
‫Entonces, setImmediate, y al igual que el otro temporizador, recibe una función
‫de devolución de llamada.
‫Y lo único que vamos a hacer
‫es escribir uno inmediato terminado, y este no tiene
‫tiempo, porque no es
‫necesario porque como dice el nombre, es inmediato.
‫Luego, otra cosa que queremos
‫hacer es leer este archivo aquí, y luego pasar
‫una función de devolución de llamada, está bien, entonces lo
‫primero es que tenemos que requerir el módulo correcto, entonces FS, y
‫ahora fs. readFile, y queremos archivo de texto. txt,
‫y luego algo que suceda.
‫Y al igual que antes, digamos aquí,
‫en este caso, la E / S terminó, está bien.
‫Entonces E / S porque esta devolución
‫de llamada aquí está realmente relacionada con una tarea de E / S,
‫que en realidad obtiene su propia fase en el bucle de eventos, ¿verdad?
‫Y finalmente, agreguemos una consola. inicie sesión aquí,
‫diciendo bueno, hola desde el código de nivel superior.
‫De acuerdo, y el código de nivel superior, porque en realidad es
‫el único que no está dentro de ninguna devolución de llamada.
‫Entonces, en este pequeño ejemplo que tenemos por ahora,
‫intentemos averiguar qué debería suceder primero.
‫Bueno, recuerde que el primer paso
‫cuando cargamos un módulo es que su código de
‫nivel superior se ejecuta, así que de inmediato
‫deberíamos ver esta consola. log here, correcto, solo entonces
‫más tarde deberíamos ver los otros registros provenientes de estas
‫otras devoluciones de llamada, porque estas devoluciones de
‫llamada realmente se ejecutarán en el bucle de eventos.
‫Así que intentemos ver si ese es
‫realmente el caso, y luego analicémoslo un poco mejor incluso.
‫Entonces, abro la consola aquí, y nuevamente, lo
‫hago usando la terminal, o
‫en realidad en la vista, así que esta terminal aquí, está bien.
‫Así que tenga en cuenta, event-loop. js, o en realidad antes
‫de hacerlo, necesito corregir este error tipográfico aquí, por lo que es un
‫archivo de prueba, no un archivo de texto.
‫Bien, pero ahora estamos listos para ejecutar este
‫comando, y los resultados están, por lo que el primer registro
‫que tenemos aquí es un saludo desde el código de nivel
‫superior, y eso era lo esperado,
‫correcto, porque este es un código que se ejecuta. inmediatamente.
‫Luego, después de eso, tenemos estas tres salidas, pero en realidad no están
‫en un orden en particular, y eso se debe
‫a que este código aquí, entonces este
‫código, en realidad no está en un ciclo de E / S,
‫por lo que no se está ejecutando dentro del ciclo de
‫eventos, porque no se ejecuta dentro de ninguna función de devolución de llamada.
‫De acuerdo, en su computadora, es posible que vea este
‫registro aquí antes que
‫este, y luego este aquí es solo
‫el último porque este tipo de archivo grande aquí toma
‫algo de tiempo para leerse, por lo
‫que probablemente siempre será el último uno.
‫Entonces, nuevamente, en este punto, el orden de estos tres aquí no tiene nada
‫que ver con el ciclo de eventos, porque
‫en realidad todavía no se
‫están ejecutando dentro del ciclo de eventos.
‫Para eso, tendremos que moverlos, o al menos
‫mover estos dos aquí, dentro de una función de devolución de llamada.
‫Y entonces, para eso vamos a usar este de aquí.
‫Así que déjame ponerlo aquí, y decir temporizador dos y temporizador dos aquí,
‫o dos inmediatos, y también agregaré otro temporizador aquí, así que el temporizador
‫tres, y este se ejecutará durante
‫tres segundos, por lo que son 3000 milisegundos. .
‫Probemos ahora el resultado de este.
‫Pero antes de hacer eso, pensemos
‫realmente por qué, justo después de que se ejecutó
‫todo el código anterior, el programa salió y volvió al indicador aquí.
‫Así que recuerda cómo Node. js decide si
‫debe continuar ejecutando el bucle de eventos, bueno,
‫lo hace preguntando si todavía hay tiempo ejecutándose en
‫segundo plano, y si es así, no terminará, y si
‫todavía hay un temporizador pendiente, bueno, entonces
‫no lo es. va a salir del programa.
‫Pero si no lo hay,
‫que fue el caso en el primer ejemplo aquí,
‫inmediatamente sale del programa, está bien, pero ahora
‫tenemos un temporizador aquí, por lo que
‫este funcionará durante tres segundos, así que intentemos
‫averiguar qué sucede aquí.
‫Bien, entonces ve que no está
‫saliendo, y solo ahora, después de que el temporizador
‫tres haya terminado, salió de la aplicación.
‫Bien, veamos eso de nuevo, para que todos
‫estos cronómetros de registros se estén ejecutando, el cronómetro
‫finalizó y salió de la aplicación.
‫Ahora, sobre estos resultados aquí, hagamos que
‫esto sea un poco más
‫fácil de ver y agreguemos solo un pequeño separador aquí.
‫Está bien, limpia esto, está bien.
‫Entonces, estos cuatro aquí son las salidas que realmente no
‫se estaban ejecutando en el bucle de
‫eventos, pero estos tres aquí realmente
‫estaban saliendo del bucle de eventos, así que ahora analicemos estos resultados.
‫Ahora, si recuerdas el
‫diagrama de la lección anterior, probablemente habrás
‫pensado que el temporizador, por lo que el temporizador dos aquí, debería
‫terminar antes del setImmediate, porque en el
‫diagrama, en realidad apareció primero justo en la
‫parte superior de la bucle de eventos.
‫Así que tenemos que establecer el tiempo de
‫espera aquí con cero, que debería ser lo mismo que setImmediate, correcto.
‫Entonces, ¿por qué
‫setImmediate aparece antes de setTimeout?
‫Bueno, hay algo que realmente no
‫expliqué en el último video, porque no quería
‫hacerlo aún más confuso, y es que el bucle de eventos
‫en realidad espera que sucedan cosas en la fase de encuesta.
‫Entonces, en esa fase donde se manejan las devoluciones de llamada de E / S.
‫Entonces, cuando esta cola de devoluciones de llamada está vacía, que
‫es el caso en nuestro ejemplo ficticio aquí,
‫entonces no tenemos devoluciones de llamada de
‫E / S, todo lo que tenemos son estos temporizadores, bueno,
‫entonces el bucle de eventos esperará en esta fase hasta que haya expirado Temporizador.
‫Pero, si programamos una devolución de llamada usando setImmediate, entonces esa
‫devolución de llamada se ejecutará inmediatamente después de
‫la fase de sondeo, e incluso
‫antes de que expiren los temporizadores, si hay uno.
‫Y en este caso, el temporizador expira de inmediato, por lo
‫que después de cero segundos, pero nuevamente, el bucle
‫de eventos realmente espera, por lo que se detiene en la fase de sondeo.
‫Y entonces esa devolución de llamada
‫setImmediate se ejecuta primero, por lo que esa es la razón
‫por la que tenemos este inmediato aquí después de que tenemos los temporizadores.
‫Está bien, y sé que esto suena muy confuso, y estoy
‫completamente de acuerdo, pero en realidad esa es
‫la forma en que Node. js funciona.
‫Y ahora hagamos esto un poco más confuso y
‫agreguemos el proceso. nextTick de la
‫que hablamos también en la última conferencia.
‫Entonces decimos proceso. nextTick, y luego, como antes, simplemente le pasamos
‫una función de devolución de llamada.
‫Y de nuevo, solo quiero iniciar sesión en
‫la consola, y voy a decir proceso. nextTick.
‫Entonces, ¿qué crees que pasará en este caso?
‫Continúe y adivine, y una vez que esté listo,
‫puede ejecutar esto, así que hagámoslo.
‫Guárdelo aquí primero, ejecútelo, y aquí vamos.
‫Entonces, los resultados están nuevamente, y ahora la primera
‫devolución de llamada que se ejecutó fue en realidad esta función aquí.
‫Por eso tenemos el proceso. siguiente Marque a
‫la derecha en el primero.
‫Entonces, ¿por qué esta función de devolución de llamada del proceso. siguiente ¿Marque el
‫primero de todos ellos en ejecutarse?
‫Bueno, recuerde que nextTick es parte
‫de la cola de microtareas, que se ejecutan después de
‫cada fase, por lo que no solo después de un tick completo.
‫Entonces, lo que sucedió aquí es que esta función
‫de devolución de llamada realmente se ejecutó antes de la fase en la que se ejecutó esta
‫función de devolución de llamada aquí, y la fase anterior, está bien.
‫Ahora nextTick es en realidad un nombre engañoso, porque un tick es
‫en realidad un ciclo completo, pero nextTick en
‫realidad ocurre antes de la siguiente fase de ciclo, y no
‫todo el tick, así que eso es lo que estaba diciendo antes.
‫Luego, por otro lado, setImmediate te haría pensar que
‫su devolución de llamada se ejecutaría de inmediato, pero
‫en realidad no es así, ¿verdad? SetImmediate
‫en realidad se ejecuta una vez
‫por tick, mientras que nextTick se ejecuta inmediatamente.
‫Entonces, sus dos nombres deberían cambiarse.
‫Deberían ser al revés, y esto
‫puede causar mucha confusión, por
‫lo que es mejor ceñirse siempre a uno de ellos,
‫que generalmente es setImmediate y no process. nextTick.
‫De todos modos, como mencioné en un último
‫video, estos mecanismos son en realidad más para casos de uso
‫bastante avanzados, por lo que
‫probablemente no los usaremos en nuestro proyecto.
‫Pero si desea obtener más información
‫sobre ellos, siempre puede leer la documentación oficial de Node.
‫Bien, con esto hemos simulado algunos aspectos del
‫bucle de eventos, pero para terminar, quiero presentar
‫rápidamente algo sobre el grupo de
‫subprocesos también, y para eso vamos a hacer
‫una operación más compleja que en realidad se
‫descargará en el grupo de subprocesos y
‫observe cuánto tardan en ejecutarse estas operaciones y cómo podemos cambiar
‫el tamaño del
‫grupo de subprocesos del que hablamos antes.
‫Así que usaremos algo de
‫criptografía aquí para encriptar básicamente una contraseña.
‫Ese es un nuevo paquete que no
‫habíamos usado antes, y se llama Crypto, pero mencioné anteriormente que
‫en realidad, todas las funciones de este paquete, serán
‫descargadas automáticamente por el bucle de eventos al grupo de subprocesos,
‫y eso es lo que nosotros
‫voy a probar ahora.
‫Y usemos esto ahora, así que cripto. pb, entonces usaremos una función
‫de cifrado llamada pbkdf2, un nombre un poco extraño,
‫y ahora pasamos la cadena secreta, que digamos contraseña, luego
‫necesitamos una cadena para resolver las contraseñas y las implementaciones
‫aquí realmente no importa, así que por ahora
‫no voy a entrar en detalles de cómo funciona
‫esto, lo haremos más tarde, está
‫bien, aquí solo necesitamos la longitud de la clave,
‫así que este número aquí es
‫solo para el
‫número de iteraciones, entonces esta es la longitud de la clave,
‫y finalmente el algoritmo, que
‫se utilizará para cifrar la contraseña.
‫Por lo tanto, estos números simplemente
‫aumentarán el tiempo necesario para el cifrado.
‫De acuerdo, y finalmente, también se necesita una función de devolución de llamada, y todo lo que voy
‫a hacer aquí es hacer otra consola. log
‫y solo diga contraseña cifrada.
‫Ahora, para el propósito de esta
‫demostración, en realidad quiero mostrarles cuánto tiempo toma
‫cada una de estas operaciones, así que
‫lo que vamos a hacer es básicamente definir una variable al
‫principio, configurarla a la fecha. ahora, esa es la fecha actual en
‫milisegundos, y luego aquí, todo lo que tenemos que hacer es registrar no
‫solo la cadena, sino también la fecha. ahora, que será la fecha en
‫este punto en milisegundos, menos el inicio, y
‫entonces eso nos dará la cantidad de
‫milisegundos que han pasado para
‫hacer este cálculo.
‫Bien, probémoslo, guarde
‫y ejecútelo de nuevo, y aquí puede ver
‫que tomó 1855 milisegundos, casi
‫dos segundos para encriptar esta contraseña.
‫Bien, pero ahora vamos a duplicar este código,
‫o en realidad quiero cuatro
‫instancias de esto para mostrarte algo.
‫Entonces, si ejecutamos esto ahora, probablemente debería tomar aproximadamente la misma
‫cantidad de tiempo, y sí, así que
‫fue 1. 8
‫segundos, ahora son 2. 2 segundos, que es bastante similar.
‫De acuerdo, y recuerde que le dije en una
‫de las conferencias anteriores, que por
‫defecto el tamaño del grupo de subprocesos es
‫cuatro, por lo que hay cuatro subprocesos
‫haciendo el trabajo al mismo tiempo, y
‫por eso estos cuatro cifrados de contraseña
‫toman aproximadamente al mismo
‫tiempo y suceden básicamente todos al mismo tiempo.
‫Pero en realidad podemos cambiar el tamaño de ese grupo de subprocesos.
‫Entonces, permítanme mostrarles cómo hacemos eso, y lo
‫hacemos diciendo proceso. env, y esa
‫es una variable ambiental, y nuevamente
‫hablaremos más sobre eso más adelante, y
‫UV, que significa LibUV, tamaño
‫de grupo de subprocesos, por lo que si configuramos esto en uno,
‫solo tendremos un subproceso en nuestro grupo de subprocesos.
‫Intentémoslo de nuevo y veamos qué sucede ahora.
‫Entonces ves que todos tardan mucho más en calcularse.
‫Básicamente, se calculan uno tras otro.
‫Entonces este es el primero, luego este aquí toma el
‫doble de tiempo, y nuevamente eso es
‫porque este solo puede comenzar tan pronto como
‫se complete el primero, y lo mismo con
‫el tercero y el cuarto.
‫Ahora digamos que lo
‫cambiamos a dos, entonces deberíamos ver los
‫dos primeros con el mismo tiempo, y exactamente,
‫los dos segundos también con un tiempo similar.
‫Entonces eso tiene sentido, ¿verdad?
‫Solo para completar aquí, ahora
‫lo mismo con tres, por lo que estos tres tienen
‫un tiempo similar, y luego el último.
‫Muy bien, así es como funciona básicamente el grupo de subprocesos, así que
‫decidí no solo centrarme en el bucle de eventos, sino
‫también darles una descripción general, muy rápida, del grupo de subprocesos y cómo
‫podemos cambiar el tamaño del grupo de
‫subprocesos. , está bien, tenga en cuenta que
‫este código aquí en realidad
‫todavía es asincrónico, porque pasamos una función de devolución de llamada.
‫De acuerdo, y podríamos usar la versión síncrona, pero
‫eso bloquearía el ciclo de eventos.
‫¿Quieres ver eso?
‫Así que permítanme mostrarles eso muy rápidamente también, de
‫modo que uno no estaba realmente planeado,
‫pero hagámoslo de todos modos, porque es
‫muy interesante ver eso, creo.
‫Bien, entonces eso funcionará así.
‫Usamos nuevamente la versión sincronizada de la misma función, que
‫una nota, está muchas veces disponible.
‫Recuerde que tenemos lo mismo para el archivo de lectura, por
‫lo que hemos leído el archivo, que acepta una
‫devolución de llamada, y hemos leído la sincronización de archivos, que es
‫la versión sincrónica que no acepta ninguna devolución de llamada, así que así.
‫Entonces, este cifrará la contraseña,
‫bloqueará la ejecución del código y luego pasará a la siguiente
‫línea, que luego registrará esto aquí en la consola.
‫Ahora dupliquemos esto aquí.
‫Eso fue demasiado, deshágase de este aquí, por lo
‫que ahora estos cuatro cifrados de contraseña ya no se ejecutarán
‫en el bucle de eventos.
‫Y, por lo tanto, ya no se descargarán al grupo de subprocesos.
‫Bien, y ahora, incluso si tenemos un tamaño de
‫grupo de subprocesos de cuatro, veamos qué sucede.
‫Como puede ver, suceden de forma completamente sincrónica.
‫Entonces, uno tras otro, y lo que es aún
‫peor, es que todos
‫estos temporizadores aquí, incluso nextTick y el
‫inmediato, solo aparecieron después de que ocurrieron las encriptaciones de contraseñas.
‫Así que esto realmente estaba bloqueando toda la ejecución, incluso
‫si este temporizador aquí, por ejemplo, este aquí,
‫se terminó después de cero segundos,
‫y este después de tres
‫segundos, pero todos tienen que esperar siete
‫segundos hasta que todas estas encriptaciones de
‫contraseñas aquí estén disponibles. finalmente listo, de nuevo porque no se estaban
‫ejecutando dentro del bucle de eventos, pero sí.
‫Básicamente, estaban trabajando en segundo plano y solo podían
‫ser recogidos por el bucle
‫de eventos cuando estaban listos, justo después
‫de estas cuatro encriptaciones de contraseña, por lo
‫que este fue otro gran ejemplo de ver
‫el bloqueo de código y el bucle de eventos en acción.
‫Bien, eso fue suficiente para una conferencia, espero que les
‫haya resultado interesante y
‫nos vemos en la próxima.