Cuando se trata de sincronismo, una buena forma de pensar es sobre estado . Estado es lo que se debe conservar en el almacenamiento de datos (que puede ser RAM, disco, ... lo que sea, y no necesariamente en el servidor) para que el procesamiento pueda continuar y tener éxito.
Al hacer llamadas síncronas (genéricamente, no específicamente con Node.js), el llamante es un hilo de ejecución en alguna máquina, y el "estado" es lo que ese hilo de ejecución "sabe": su Posición actual en el código, sus variables locales, su pila de llamadas. La persona que llama conserva ese estado en la RAM durante la duración de la llamada; esa es la definición de una llamada síncrona: mientras la llamada no se termina, la persona que llama queda bloqueada. Los detalles pueden variar según el lenguaje de programación y cómo se interpreta / compila, pero para la mayoría de los lenguajes, cada hilo de ejecución (un concepto de lenguaje) se asigna en un hilo del sistema (un concepto de sistema operativo), que significa que el estado incluye una entrada en la tabla de subprocesos del sistema, un poco de espacio en las estructuras del programador y la pila de subprocesos .
Cada hilo del sistema tiene su propia pila, asignada cuando se creó el hilo. El tamaño predeterminado para esta pila depende del sistema operativo y puede ajustarse mediante programación. En Linux, una pila de hilos tiene un tamaño 1 MB de forma predeterminada. Eso es 1 MB de espacio de direcciones , no de RAM: las páginas reales se asignan cuando se accede a ellas, por lo que un hilo típico utilizará solo unas pocas docenas de kilobytes de "RAM verdadera". Aunque los detalles varían mucho según el contexto, la conclusión es la siguiente: en una aplicación típica, normalmente puede manejar unos pocos cientos de subprocesos a la vez, lo que significa que su servidor puede alojar unos pocos cientos en curso llamadas síncronas simultáneamente . Más allá de eso, debes pensar.
Llamadas asíncronas elimina esta gestión de estado basada en subprocesos: la persona que llama recupera el control inmediatamente y, por lo tanto, puede hacer otra cosa o incluso salir. Sin embargo, aún debe mantener algún estado en algún lugar, aunque solo sea para recordar que hay una llamada en curso y saber qué se debe hacer con el resultado. El punto de ir asíncrono es hacer una administración manual y precisa de este estado, que puede ser tan pequeño como un ID de sesión de 16 bytes o algún estado central similar, permitiendo así muchas más llamadas simultáneas. Dependiendo del contexto, es posible que incluso pueda descargar el estado en el cliente (lo que implica problemas de seguridad adicionales, por supuesto). Sin embargo, la implementación se vuelve mucho más compleja cuando se hace asíncrono, y la complejidad generalmente conlleva trabajo adicional, errores adicionales y, por lo tanto, vulnerabilidades adicionales.
Por lo tanto, ir asíncrono es una optimización y, por lo tanto, debe preverse solo si la situación hace que valga la pena la complejidad y el esfuerzo adicionales. Al igual que con todas las cosas relacionadas con el rendimiento, dichas optimizaciones deben retrasarse hasta que un problema grave real relacionado con el rendimiento haya sido debidamente detectado, monitoreado y medido. "La optimización prematura es la raíz de todo mal".
Por lo tanto, sugiero que primero escriba todo su código de forma sincrónica. Entonces, y solo entonces, las pruebas de rendimiento realistas le dirán si las llamadas sincrónicas serán suficientes o no; y si está justificado ir asíncrono, en ese momento sabrá mucho más acerca de su propia aplicación, lo que le permitirá estar preparado (o al menos más listo) para abordar la complejidad inherente de la programación asíncrona.