Video Summary and Transcription
Esta charla explora el uso de trabajadores web en React para mejorar la experiencia del usuario y el rendimiento. Discute las limitaciones de la representación de JavaScript y cómo los trabajadores web pueden descargar tareas a hilos separados. La charla también destaca los beneficios de usar el modo concurrente en React e introduce la biblioteca UseWebWorkerHook para simplificar la creación de trabajadores web. Enfatiza las consideraciones al usar trabajadores web y concluye con una mención de la contratación de Postman y la liberación de una nueva característica.
1. Introducción y Antecedentes
Soy Nikhil, un ingeniero en Postman, especializado en sistemas de diseño y rendimiento a escala. Conectemos en Twitter y GitHub.
Hola a todos. Gracias por la increíble introducción. Estoy súper contento y emocionado al mismo tiempo de estar aquí virtualmente en React Berlín y poder compartir mis pensamientos con todos ustedes. Como habrán recibido la introducción de nuevo, soy Nikhil, y trabajo como ingeniero en Postman. Principalmente manejo cosas alrededor de los diseño sistemas, Postman en la web, y la plataforma de escritorio de Postman. Así que si quieres hablar conmigo sobre performance diseño sistemas a scale en general, me encanta hablar de esos temas, por cierto. Así que ven a saludar. Me encantaría conectar en Twitter, en GitHub. Creo que podrías ver las etiquetas relevantes, cómo puedes conectarte conmigo. Así que nos encantaría tener una charla.
2. Multi-Threading en React y Experiencia de Usuario
En esta sesión, responderé a la pregunta de si React puede ser multihilo y cómo puede mejorar la experiencia del usuario. Las aplicaciones de carga lenta y no responsivas pueden llevar a que los usuarios se vayan. Comprendamos el problema a través de una demostración y analicemos la causa raíz del problema, que involucra el bucle de eventos y las tareas de larga duración.
Bien. Antes de sumergirnos en la presentación, me gustaría dar una breve descripción general de lo que voy a hablar aquí. Entonces, en esta sesión, intentaré responder a una pregunta muy simple, que es, ¿puede React ser multihilo o no? ¿Tiene esas capacidades de multihilo y si las tiene, cómo nos puede ayudar a mejorar Bien. Voy a comenzar la charla con una de las afirmaciones muy nobles, que es que la experiencia del usuario es importante, ¿verdad? Entonces, lo que significa una buena experiencia de usuario es que es muy agradable para los usuarios realmente usar diferentes partes de sus aplicaciones, como diferentes características con una experiencia muy fluida. No tienen que buscar cómo hacer algo. No tienen que esperar a que suceda algo, cosas así. ¿Verdad? Entonces, la experiencia de usuario siempre es beneficiosa para su producto y para generar negocios para él, ¿verdad? Porque los usuarios siempre están contentos si su producto es todo fluido.
Y también para hablar de ello en la extensión de ello, ¿verdad?, se realizó una encuesta que mostró varias razones por las que los usuarios se van, como que dejan de usar una aplicación. Entonces, si ves en estas varias razones, una de las principales razones que fue, fue la carga lenta, que es como el 88% de los usuarios realmente sintieron que no quieren usar su producto si se carga muy lento, pero no queremos hablar de eso en nuestra sesión. Lo que queremos enfocar más en esto es este círculo amarillo que ves que es el 73% de los usuarios no usan una aplicación o la abandonan porque es no responsiva o es mucho más inestable. Y sabemos que la experiencia de usuario siempre es beneficiosa para tus usuarios, como mencioné, ¿verdad? Entonces, sabes, en este caso, si caes en cualquiera de estas categorías y la experiencia de usuario no es tan buena, ¿verdad?, tus usuarios podrían estar haciendo rage quits o como que podrían no querer usar esa aplicación en sí. Entonces, no quieres que esos tengan una experiencia así, ¿verdad? Siempre quieres que estén contentos. Y esto es lo que quieres hablar en nuestra charla.
Entonces, intentemos entender el problema rápidamente y te mostraré exactamente qué tipo de problema del que estoy hablando. Entonces, si voy a la demostración, verás esta pequeña aplicación muy bonita, que te muestra un bonito spinner de React que está girando solo para mostrarte cuando nuestra aplicación se vuelve no responsiva. Entonces, hay esta gran lista de elementos que tengo, y no hay nada sofisticado en ella. Solo son algunos elementos, quiero ordenarlos. Y he mantenido inicialmente la lógica de ordenación para ser súper lenta, que es como el ordenamiento burbuja en este caso, y que está destinado a mostrarte la experiencia de un mal y inestable UX, de hacer una tarea que es muy grande. Entonces, si hago clic en este botón, que es la antigua forma de hacerlo, voy a realizar un ordenamiento en esta gran lista de elementos. Y dado que ese elemento va a tomar demasiado tiempo, veamos qué le sucede a la experiencia de usuario en esa aplicación, ¿verdad? Entonces, hago clic en este botón. Ahora mi aplicación está completamente congelada. No puedo hacer nada. Hago clic en No puedo hacer clic en los botones. Y esto es muy malo. Entonces, después de algún tiempo y esto se hace, ahora el spinner vuelve a su estado de giro, que es como durante algún tiempo, mi aplicación estuvo completamente atascada. Entonces, este es realmente el problema.
Ahora, intentemos hacer un análisis de causa raíz de lo que salió mal, y qué podría haberse mejorado cuando estabas construyendo este tipo de experiencia. Entonces, miremos un diagrama muy simple, que muestra el funcionamiento actual de nuestro bucle de eventos lado. Lo que nuestro bucle consta de es tu código JavaScript, tu bucle de eventos es como una pila, o no exactamente una pila, simplemente toma cierta cantidad de operaciones, ya sean algunas funciones de JavaScript o algunos otros eventos, como eventos de mouse, eventos de clic, y simplemente comienza a atender a ellos uno por uno, ¿verdad? Y si hay algún evento que es súper grande, en ese caso nuestro bucle de eventos está todo atascado. Y tus usuarios no pueden hacer nada más debido a esta tarea de larga duración, ¿verdad? Y dado que tu bucle de eventos está todo ocupado, y tu JavaScript está tomando demasiado tiempo para liberarse, tu UI va a parecer que está completamente congelada, y tus usuarios no pueden hacer nada hasta que esta gran tarea esté toda hecha o no.
3. Renderizado de JavaScript y Web Workers
Para mejorar la experiencia del usuario, es importante asegurar que JavaScript se ejecute y renderice los marcos dentro del tiempo asignado. Si JavaScript tarda más, se pueden omitir los marcos subsiguientes, resultando en una experiencia irregular. Para abordar esto, se pueden utilizar los web workers para delegar tareas más grandes a hilos separados, permitiendo que el hilo principal permanezca desbloqueado. Al crear una instancia de worker y enviar mensajes al hilo del worker, las tareas se pueden ejecutar en paralelo, mejorando el rendimiento.
Entonces, ese es exactamente el problema, es este evento muy grande que está llegando. Ahora, para respaldar mi afirmación, hagamos un cálculo rápido de cómo todo esto se alinea en un lugar central, ¿verdad? Entonces, si ves ese spinner en nuestra demostración que mostramos, ¿verdad? Si quieres que se haga a 60 fotogramas por segundo, eso significa que tendríamos mil milisegundos para renderizar 60 fotogramas, ¿verdad? Esa es la matemática. Y eso significa que tienes 16 milisegundos para que tu JavaScript se ejecute por fotograma.
Ahora, para hablar más realísticamente, los navegadores suelen tomar cuatro o seis milisegundos de este tiempo de 16 milisegundos, que son sus tareas internas, composición, pintura, comprensión de cómo analizar HTML, JavaScript y cosas así. Así que, en términos generales, tu JavaScript en realidad solo tiene de 10 a 12 milisegundos o menos para ejecutarse y renderizar ese fotograma en un tiempo constante y evitar el retraso.
Ahora, intentemos ver este pequeño ejemplo de cómo tu código realmente pasa por el pipeline de un navegador, qué es exactamente lo que va a suceder cuando se ejecute tu JavaScript, cuando se ejecute tu CSS, y cuando todo esté compilado. Entonces, todo esto, si lo ves en un solo fotograma, todo esto tiene que hacerse en 16 milisegundos o menos tiempo. Así que tu navegador tiene que ejecutar JavaScript, tiene que calcular cuáles son los estilos, cuál es el CSS para ello, tiene que renderizar todo el CSS, preparar el DOM, tiene que componer todo y analizar todo y mostrar el resultado final en tu página web. Ahora, a medida que sigues añadiendo más JavaScript, ya sea que, no estamos usando solo JavaScript ahora. Tal vez estamos usando CSS y el motor JS como componentes de estilo, estamos usando tal vez leer nosotros o una biblioteca llamada React. Sin mencionar que React, añadir React puede añadir tiempo a tu ejecución de JavaScript. Pero la intención detrás de este ejemplo es que cuanto más tiempo vaya a tomar tu JavaScript, más tiempo se va a extender para que tu navegador pueda ponerse al día con esto. Porque todo esto tiene que hacerse en 16 milisegundos. Si tu JavaScript está tomando más tiempo, vas a superar ese límite de tiempo de 16 milisegundos. Y como tus fotogramas subsiguientes también tendrán que ponerse al día, tu navegador necesita omitir algunos de los fotogramas intermedios para ponerse al día con la velocidad de ejecución de este JavaScript y también atender a los otros fotogramas que están llegando. Y debido a eso, como mencioné, necesita omitir los fotogramas. Y eso es exactamente lo que es un jank, porque solo ves un spinner que no se mueve, porque tuvo que omitir todos los fotogramas para ponerse al día con la velocidad, ¿verdad? Y ese era exactamente el problema allí.
Ahora, volviendo al problema, que era que había una tarea muy grande que estaba bloqueando tu bucle de eventos, ¿verdad? Ahora, si tuviera que sacar esto de mi bucle de eventos, ¿verdad?, y evitar que no bloqueara, mi problema se resolvería, ¿verdad? Así que las otras tareas más grandes pueden seguir funcionando en un contexto separado, mientras que mi bucle de eventos está todo libre. Así que ninguna tarea más grande está bloqueando mis páginas web, UX o como que no está bloqueando o no está entorpeciendo la experiencia. Y esta es exactamente la ideología de un web worker, ¿verdad? En términos simples, los web workers nos permiten trabajar en paralelo utilizando hilos separados, ¿verdad? Esa es como la analogía más simple. Así que puedes hacer más cantidad de cosas en algún contexto paralelo o hilos paralelos para evitar que tu hilo principal se bloquee, ¿verdad? Y puedes dar todas esas tareas más grandes a tus hilos de worker.
Ahora, si quiero mostrarte cómo funciona todo esto, ¿verdad? Entendamos la pequeña analogía. Hay tu aplicación React que se está ejecutando en un hilo totalmente diferente. Y hay un hilo de worker que es, de nuevo, un contexto totalmente separado. Ahora, lo que sucede es que creamos una instancia de worker utilizando la nueva API de workers. Y el worker que obtenemos, enviamos un mensaje a nuestro hilo de worker, que se hace mediante la API worker.postMessage. Así que le enviamos un mensaje que, hey, hay una tarea grande que necesitas hacer. Y el worker lo recibe porque adjuntamos un eventlistener en el lado del worker, que es self.eventlistener. Así que asegúrate de que los workers no tienen acceso a tu ventana.
4. Trabajadores de React y Gestión de Recursos
El hilo principal de React no se bloquea mientras los trabajadores manejan la gran tarea. El trabajador envía un mensaje de vuelta a la aplicación de React cuando ha terminado, y el resultado se muestra en la interfaz de usuario. Para liberar recursos, el trabajador se termina.
Solo tiene acceso a un objeto global llamado this, ¿verdad? Entonces, en el event listener, escucha que, oh, React me está diciendo que haga algo. Déjame hacer ese trabajo. Y mientras tanto, el hilo principal de React no está bloqueado porque toda la gran tarea está siendo realizada por los trabajadores. Y si se hace a tiempo, el trabajador luego envía un mensaje de vuelta a tu aplicación de React. Y tu aplicación de React vuelve a escuchar que, oh, ahora, el trabajador ha completado algo, y para hacer algo en mi UI para mostrar si está hecho o no. Y luego el resultado se muestra en la aplicación de React. Y finalmente, cuando todo está hecho, también queremos liberar todos los recursos de los usuarios porque un trabajador también está utilizando los recursos del usuario para ejecutarlo como un hilo separado, así que hacemos worker.terminate, que es una buena práctica a seguir.
5. Modo Concurrente y Trabajadores Web
En el modo concurrente, React puede alternar entre tareas prioritarias, lo que da la sensación de paralelismo pero en realidad utiliza el cambio de contexto. JavaScript es de un solo hilo, pero los trabajadores web pueden ejecutarse en núcleos de CPU separados, lo que permite una funcionalidad similar a la de múltiples hilos. Sin embargo, hay obstáculos para usar trabajadores web fácilmente, como el paso de mensajes complejos y la coordinación entre trabajadores. Las promesas pueden ser una solución, ya que permiten una detección más fácil de la finalización y la actualización de la interfaz de usuario. Una biblioteca que puede ayudar con esto es Commlink.
Ahora, la pregunta del millón de dólares, ¿no lo hace todo el modo concurrent? Porque también maneja cosas como hacer cosas, que toman más tiempo o un contexto similar como los web workers. ¿Qué hacen los web workers que es diferente a esto? Entonces, si te doy un rápido resumen de lo que era el modo concurrent, si imaginas que hay un producto aplicación de búsqueda donde escribes algo y la lista del producto se actualiza en base a tu consulta de búsqueda. Muestra que hay un evento de usuario, como un tipo, y hay una fase de renderizado donde la aplicación React tiene que actualizar tu UI basada en la búsqueda que hiciste. Y esa fase de renderizado, que es esta gran franja amarilla, es ininterrumpible. Porque React no tenía la capacidad de saltar a una tarea específica de prioridad, que era manejar ese evento de usuario antes de hacer la parte de renderizado. En el nuevo modo concurrent, esta franja amarilla puede ser desglosada, lo que significa que React puede cambiar, pausar su renderizado, e ir a una tarea de prioridad diferente, que era un evento de usuario. Así que atender a eso, mostrar que el tipo está funcionando bien, y luego reanudar su renderizado. Si entiendes esta analogía del modo concurrent, la diferencia que reside en es el paradigma en sí, que es el modo concurrent en primer lugar siendo cambio de contexto. Está haciendo la misma tarea, pero está creando sub-tareas de esas, y está cambiando entre los contextos. Así que parece que es paralelismo, pero en realidad es solo cambio de contexto y está haciendo la tarea de una manera sincrónica.
Mientras que, el paralelismo en general no es cambio de contexto en sí mismo, es como utilizar diferentes recursos de tu CPU para hacer una cantidad diferente de tareas. Así que en el primer ejemplo, solo estoy haciendo una tarea. Pero en realidad, el paralelismo puede hacer cualquier número de tareas en paralelo. Otra pregunta que surge ahora es, ¿cómo hacer multi-hilo incluso si es posible? Porque JavaScript en sí mismo es de un solo hilo, ¿verdad? ¿Cómo puedes hacer esto? Así que necesitamos entender el hilo y la CPU como dos entidades también diferentes para entender esa respuesta mejor. Un hilo es una entidad totalmente diferente. Un núcleo de CPU, que puede abrir un hilo, es un juego de pelota totalmente diferente. Así que puedes ver que antes, nuestras máquinas solían ser de un solo núcleo. Pero ahora, en la nueva era de los ordenadores, tienes máquinas multicore, ¿verdad? Así que lo que queremos hacer es que nuestra aplicación React se ejecute en un núcleo de CPU totalmente separado, ¿verdad? Nuestro trabajador web, que es de nuevo una cosa de un solo hilo, pero está funcionando dentro de un totalmente diferente núcleo de CPU en sí mismo. Lo que significa un contexto de ejecución totalmente diferente, y todos están trabajando en términos de pasar mensajes a uno y otro para comunicar cuando el trabajo está hecho. Así que es de un solo hilo, pero como de múltiples hilos, ¿verdad? Así que entiendes por qué funciona como una cosa de múltiples hilos. Así que estamos utilizando los recursos de los usuarios de diferentes núcleos y estamos ejecutando estos dos diferentes mundos totalmente fuera de estos núcleos. Así que ya que estos aportan tanto a la mesa, ¿por qué no los usamos, es la siguiente pregunta. Así que personalmente descubrí que hay muchos obstáculos que nos hacen no usar web workers de una manera más fácil. Así que si ves, un ejemplo es que tienes un trabajador web, pero tienes que crear un mensaje-pasando instancia en él, ¿verdad? Tienes que crear un, tienes que configurar los oyentes de eventos y tus trabajadores y tu aplicación principal de React tiene que escuchar el paso de los oyentes de eventos en él, que es como algo adicional code que no me gusta. En cambio, ¿no hubiera sido mejor que solo necesitaras crear una función dentro de tu trabajador y cuando creas una instancia del trabajador en el hilo principal, solo haces worker. esa función que creaste, que es mucho más simple, ¿verdad? Otro tipo de problema que vi es cómo saber cuándo el hilo del trabajador está completo o no, como saber el estado, ¿todavía está funcionando? ¿Ha empezado o no? ¿Está hecho o no? Así que eso es como totalmente, es como muy difícil de hacer, diría yo, porque es, estos mensajes son como simplemente disparados y olvidados. Así que no hay una forma directa de obtener cómo actualizar tu UI basada en cuando este trabajador va a completarse. Y una extensión a este problema es en realidad una de las otras cosas clave que descubrí, que es cómo coordinar entre los web workers, ¿verdad? Porque si ves en este ejemplo, hay un trabajador que está haciendo una tarea, hay otro trabajador haciendo alguna otra tarea. Y luego hay un tercer trabajador que en realidad está esperando que la primera y la segunda tarea se completen, ¿verdad? Así que es como, es como la complejidad trae, como viene cuando estás usando este tipo de architecture y como manejar demasiados web workers alrededor de eso, ¿verdad? Entonces, ¿cuál podría ser la solución obviamente promesas, ¿verdad? Así que porque el JavaScript asíncrono es tan fácil de detectar como cuando algo va a completarse, ¿verdad? Así que sería un poco más fácil si pudieras hacer un mensaje POST a un trabajador y simplemente esperar el resultado, como en lugar de devolver un valor, tu trabajador en realidad te da una promesa. Y ahora puedes saber que, okay, sé cuando va a completarse. Y luego puedo actualizar mi UI basada en eso, ¿verdad? Bueno, así que algunas bibliotecas que quiero mencionar, que es primero Commlink.
6. Uso de UseWebWorkerHook para Mejorar el Rendimiento
Existe una increíble biblioteca llamada UseWebWorkerHook que simplifica el proceso de creación de un trabajador web en React. Al definir el trabajador y utilizar la función sort worker, puedes delegar tareas que consumen mucho tiempo a un hilo separado, mejorando el rendimiento de la aplicación y la experiencia del usuario. El hilo principal queda desbloqueado y el spinner ya no se congela. Los trabajadores web son útiles para tareas intensivas de CPU.
Eso es increíble. Hay otra increíble biblioteca creada por Google Chrome Labs. Pero otra biblioteca que me gusta personalmente, que es súper útil cuando estás creando cosas con React, es UseWebWorkerHook, que son solo dos simples pasos que puedes usar para crear lo mismo, ¿verdad? Solo creas un trabajador usando UseWebWorkerHook. Le pasas la función como esa gran función que va a tomar mucho tiempo en caso de que aquí la agregué como bubble sort, ¿verdad? Y te da la instancia del trabajador. Te da una instancia de una función para matar al trabajador y todo eso. Y cuando quieras realizarlo, solo haces sort worker, que es la función aquí que obtuviste. Entonces haces el sort worker y solo pasas los datos relevantes. Y eso es todo. Solo defines el trabajador y lo usas. Y eso es todo lo que necesitas saber.
Muy bien. Así que suficiente con el conocimiento, y volvamos a la misma vieja demostración de la que estabas hablando. Así que aquí, ahora lo que haré es usar este nuevo botón que dice nueva ola. Y aquí, lo que estoy haciendo es exactamente lo mismo, que es crear un trabajador y pasar y permitir que ese trabajador haga el mismo bubble sort en su propio contexto. Así que ahora intentemos ver qué le pasa al spinner cuando intento hacer eso. Así que hago clic en esto. Ahora mi spinner no está congelado. Así que mi aplicación es nuevamente utilizable y mis usuarios están todos contentos. Mientras tanto, también pude hacer esta tarea muy grande. Y si quieres comprobar esto por rendimiento, intentemos hacer esto de nuevo y ver el seguimiento del rendimiento, ¿verdad? Así que si abro esta pestaña de rendimiento, hago clic en la carpeta donde estamos haciendo cosas, que es cuando mi aplicación se atasca debido a hacer cosas de manera sincrónica. Y si lo cierro, verás que el hilo principal está gastando el tiempo, como si lo abro aquí. Así que verás que hay un evento muy grande de 5.69 segundos que estaba bloqueando el hilo principal de la misma manera que hablamos, ¿verdad? Por eso el spinner se congela. Pero en el otro caso, si hago lo mismo con, comenzando el perfilado y haciendo clic en la web, la forma de uso del trabajador de hacer cosas, deberíamos ver que nuestro hilo principal debería estar completamente desbloqueado, ¿verdad? Así que si cierro esto de nuevo, y vemos el perfilado ahora. Veríamos que ahora esa barra muy grande no está en el hilo principal, ¿verdad? Y si lo cierro, verías que ahora el hilo del trabajador tiene esa barra muy grande. Por eso un spinner no estaba todo desordenado, ¿verdad? Porque el hilo del trabajador está atendiendo a esa tarea más grande. Muy bien. Así que con esto, creo que parecemos haber logrado algo en esto y como mejorar la experiencia del usuario en estos escenarios. ¿Verdad? Así que sí, felicidades, gran trabajo en eso. Así que algunas cosas más para mencionar. Así que hay algunas instancias en las que puedes usar trabajadores web, que es exactamente donde necesitas hacer algunas tareas intensivas de CPU.
7. Trabajadores Web y Consideraciones
Puedes asignar un trabajador para hacer todo el cálculo de qué Nodo ha sido actualizado o no, cuál es el árbol actualizado. Cada vez que veas algo que está tomando demasiado tiempo y va a bloquear tu ciclo de eventos en esto, deberíamos recurrir a la estrategia de trabajadores web. Ten precaución al elegir entre trabajadores web y otras opciones. Tareas como llamadas de red y manipulación del DOM pueden no requerir trabajadores web. Los trabajadores web no tienen acceso al objeto del documento o al almacenamiento local. Agregar más trabajadores web puede aumentar la complejidad y los esfuerzos de mantenimiento. Por último, Postman está contratando y lanzando la función WeTen. Visita el sitio web de carreras y consulta el blog para obtener más información.
Y no quieres bloquear tu UI en eso, como mencioné, ¿verdad? Lo que es, por ejemplo, la diferenciación del DOM virtual que hace React, ¿verdad? Puedes asignar un trabajador para hacer todo el cálculo de qué Nodo ha sido actualizado o no, cuál es el árbol actualizado. Entonces todos esos cálculos pueden ser dados al trabajador web. Similar a esto puede ser para la manipulación y procesamiento de imágenes y para el dibujo en canvas. Así que la esencia es la misma. Cada vez que veas algo que está tomando demasiado tiempo y va a bloquear tu ciclo de eventos en esto, deberíamos recurrir a la estrategia de trabajadores web.
Y que es de nuevo, una palabra de precaución, que es que necesitamos ser sabios en términos de elegir entre esas dos cosas, ¿verdad? Entonces, si ves tareas que están limitadas por IO, ¿verdad?, que son como tal vez llamadas de red y otras cosas, no necesitas usar web workers en esos casos, ¿verdad? Porque esas ya son asíncronas y solo añaden a la complejidad. De manera similar, si vas a la manipulación del DOM y quieres añadirlo a un trabajador web, un trabajador web no tiene acceso a tu objeto de documento, ¿verdad? De nuevo, la razón es que son diferentes CPU, diferentes contextos, como diferentes núcleos de CPU, por lo que no sabe qué es la ventana, ¿qué está haciendo el otro mundo? No sabe acerca de eso. Y de manera similar para el almacenamiento local, porque de nuevo, no tiene acceso a esa API. Y por último, pero no menos importante, no es como super, tendrías que ser super cauteloso si quieres usar web workers, ¿verdad? Porque cuando creces y como sigues añadiendo web workers, solo añade a la complejidad y puede llegar a ser super difícil mantenerlos, ¿verdad? Así que necesitas ser super cauteloso si quieres ir con este enfoque o no. Esa debería ser la decisión a tomar.
Muy bien, con esto, me gustaría terminar mi charla y espero que hayan podido obtener algunas ideas de ella. Por último, pero no menos importante, estamos haciendo cosas increíbles en Postman. Así que estamos contratando y si quieres ser parte de nuestro increíble viaje, por favor visita nuestro sitio web de carreras y creo que estaríamos encantados de tenerte a bordo. Y como mencioné acerca de lo interesante, hemos estado trabajando muy duro para lanzar la función WeTen de Postman. He tenido a muchas personas preguntándome acerca de cuáles van a ser las características. Y sé que la gente está super emocionada por este lanzamiento de WeTen. Así que si quieres saber más al respecto, por favor revisa el blog de Postman y echa un vistazo a las increíbles características que vienen. Muy bien. Así que con esto finalmente termino mi charla. Así que me gustaría agradecer a todos, a los organizadores, a la comunidad por organizar este increíble evento y por tenerme aquí. Fue increíble estar aquí. Y por último, pero no menos importante, la increíble audiencia. Así que un aplauso para todos por hacer de este evento un éxito. Así que gracias de nuevo por tenerme y disfruten de la conferencia.
Comments