¿Cómo maneja JavaScript las respuestas AJAX en segundo plano?

139

Dado que JavaScript se ejecuta en un solo subproceso, después de que se realiza una solicitud AJAX, ¿qué sucede realmente en segundo plano? Me gustaría obtener una visión más profunda de esto, ¿alguien puede arrojar algo de luz?

aziz punjani
fuente
66
Una descripción bastante buena está aquí: stackoverflow.com/questions/2914161/ajax-multi-threaded
Jonathan M
3
El código JavaScript es de un solo subproceso (excepto para los trabajadores web), pero no el navegador que ejecuta el motor JavaScript ...
Juan Mendes
@JuanMendes ¿Se ejecuta JavaScript en un hilo mientras que la Cola de eventos se ejecuta en otro hilo?
Shaun Luttin
1
@ShaunLuttin No, la cola del evento es lo que inicia JavaScript
Juan Mendes

Respuestas:

213

Debajo de las cubiertas, JavaScript tiene una cola de eventos. Cada vez que finaliza un subproceso de ejecución de JavaScript, comprueba si hay otro evento en la cola para procesar. Si lo hay, lo saca de la cola y activa ese evento (como un clic del mouse, por ejemplo).

La red de código nativo que se encuentra bajo la llamada ajax sabrá cuándo se realiza la respuesta ajax y se agregará un evento a la cola de eventos de JavaScript. La forma en que el código nativo sabe cuándo se realiza la llamada ajax depende de la implementación. Puede implementarse con subprocesos o también puede ser impulsado por eventos en sí mismo (realmente no importa). El objetivo de la implementación es que cuando se realiza la respuesta ajax, algún código nativo sabrá que está hecho y pondrá un evento en la cola JS.

Si no se está ejecutando Javascript en ese momento, el evento se activará de inmediato y se ejecutará el controlador de respuesta ajax. Si algo se está ejecutando en ese momento, el evento se procesará cuando finalice el hilo de ejecución de JavaScript actual. No es necesario que el motor de JavaScript realice ninguna encuesta. Cuando una pieza de Javascript termina de ejecutarse, el motor JS solo verifica la cola de eventos para ver si hay algo más que deba ejecutarse. Si es así, saca el próximo evento de la cola y lo ejecuta (llamando a una o más funciones de devolución de llamada que están registradas para ese evento). Si no hay nada en la cola de eventos, el intérprete JS tiene tiempo libre (recolección de basura o inactivo) hasta que algún agente externo ponga algo más en la cola de eventos y lo despierte nuevamente.

Debido a que todos los eventos externos pasan por la cola de eventos y nunca se activa ningún evento mientras javascript está ejecutando otra cosa, permanece un solo subproceso.

Aquí hay algunos artículos sobre los detalles:

jfriend00
fuente
Gracias por eso. Sospeché que este era el caso, pero es bueno saberlo con certeza. Tengo un bucle for, en el que envío muchas solicitudes 'ajax'. En mi controlador (para cada solicitud, devuelta en orden arbitrario) ejecuto un código que puede llevar algún tiempo. Es bueno saber que esto definitivamente debería funcionar.
iPadDeveloper2011
44
@telandor: los eventos se ejecutan en orden FIFO (es posible que haya algunas excepciones de caso límite, pero la intención es FIFO). Algunos eventos se tratan de manera ligeramente diferente. Por ejemplo, los eventos de mousemove no se acumulan en la cola (probablemente porque podrían desbordar fácilmente la cola). Cuando el mouse se mueve y un evento mousemove ya está en la cola y no hay otros eventos más nuevos en la cola, se actualiza con la última posición en lugar de un nuevo evento agregado. Supongo que los eventos de temporizador de intervalo probablemente también se tratan especialmente para evitar que se acumulen en la cola.
jfriend00
2
@telandor: ¿qué necesitas más explicado? Es FIFO Agregué algunos artículos de referencia más a mi respuesta. Las únicas ejecuciones de FIFO que conozco son eventos desencadenados de inmediato. Llama .focus()a un elemento y eso desencadena un par de otros eventos, como un evento de "desenfoque" en el elemento con foco. Ese evento de desenfoque ocurre sincrónicamente y no pasa por la cola de eventos, por lo que sucedería de inmediato antes de otras cosas que podrían estar en la cola de eventos. En la práctica, nunca he encontrado que esto sea una preocupación práctica.
jfriend00
2
@telandor: no hay varias colas por documento del navegador. Hay una cola y todo entra y sale en serie FIFO. Por lo tanto, los tiempos de espera y las respuestas ajax y los eventos del mouse y los eventos del teclado van todos en la misma cola. Cualquiera que se ponga en la cola primero se ejecuta primero.
jfriend00
1
@CleanCrispCode - Thx. Lo agregué como una referencia útil para mi respuesta.
jfriend00
16

Puede encontrar aquí una documentación muy completa sobre el manejo de eventos en javascript.
Está escrito por un chico que trabaja en la implementación de JavaScript en el navegador Opera.

Más precisamente, mire los títulos: "Flujo de eventos", "Cola de eventos" y "Eventos para no usuarios": aprenderá que:

  1. Javascript se ejecuta en un solo hilo para cada pestaña o ventana del navegador.
  2. Los eventos se ponen en cola y se ejecutan secuencialmente.
  3. La implementación ejecuta XMLHttpRequest y las devoluciones de llamada se ejecutan utilizando la cola de eventos.

Nota: El enlace original era: enlace , pero ahora está muerto.

qwertzguy
fuente
1

Quiero elaborar un poco, con respecto a la implementación ajax mencionada en las respuestas.

Aunque la ejecución de Javascript (regular) no es multiproceso, como se señaló bien en las respuestas anteriores, sin embargo , el manejo real del AJAX responses(así como el manejo de solicitudes) no es Javascript y, generalmente, es multiproceso. (vea la implementación de fuente de cromo de XMLHttpRequest que discutiremos anteriormente)

y explicaré, tomemos el siguiente código:

var xhr = new XMLHttpRequest();

var t = Date.now;
xhr.open( "GET", "https://swx.cdn.skype.com/shared/v/1.2.15/SkypeBootstrap.min.js?v="+t(), true );

xhr.onload = function( e ) {
		console.log(t() + ': step 3');
    
    alert(this.response.substr(0,20));
};
console.log(t() + ': step 1');
xhr.send();
console.log(t() + ': step 2');

after an AJAX request is made(- después del paso 1), luego, mientras su código js continúa ejecutándose (paso 2 y posteriores), el navegador comienza el trabajo real de: 1. formatear una solicitud tcp 2. abrir un socket 3. enviar encabezados 4. apretón de manos 5. enviar cuerpo 6. respuesta en espera 7. encabezados de lectura 8. cuerpo de lectura etc. toda esta implementación generalmente se ejecuta en un hilo diferente en paralelo a la ejecución de su código js. por ejemplo, la implementación de cromo mencionada utiliza Threadable Loader para cavar into, (también puede obtener alguna impresión mirando la pestaña de red de una carga de página, verá algunas solicitudes simultáneas).

En conclusión, diría que, al menos, la mayoría de sus operaciones de E / S se pueden realizar de forma simultánea / asíncrona (y puede aprovechar esto utilizando un wait, por ejemplo). pero todas las interacciones con esas operaciones (la emisión, la ejecución de devolución de llamada js) son todas sincrónicas.

shmulik friedman
fuente