Buena pregunta. Me encantaría decir "sí". No puedo
Por lo general, se considera que JavaScript tiene un solo hilo de ejecución visible para los scripts (*), de modo que cuando se ingresa su script en línea, escucha de eventos o tiempo de espera, usted permanece completamente en control hasta que regrese desde el final de su bloque o función.
(*: ignorando la pregunta de si los navegadores realmente implementan sus motores JS usando un hilo del sistema operativo, o si WebWorkers introduce otros hilos de ejecución limitados).
Sin embargo, en realidad esto no es del todo cierto , de manera astuta y desagradable.
El caso más común son los eventos inmediatos. Los navegadores los activarán de inmediato cuando su código haga algo para causarlos:
var l= document.getElementById('log');
var i= document.getElementById('inp');
i.onblur= function() {
l.value+= 'blur\n';
};
setTimeout(function() {
l.value+= 'log in\n';
l.focus();
l.value+= 'log out\n';
}, 100);
i.focus();
<textarea id="log" rows="20" cols="40"></textarea>
<input id="inp">
Resultados en log in, blur, log out
todos excepto IE. Estos eventos no solo se disparan porque llamaste focus()
directamente, podrían suceder porque llamastealert()
, abriste una ventana emergente o cualquier otra cosa que mueva el foco.
Esto también puede dar lugar a otros eventos. Por ejemplo, agregue un i.onchange
oyente y escriba algo en la entrada antes de que la focus()
llamada lo desenfoque, y el orden de registro es log in, change, blur, log out
, excepto en Opera donde está log in, blur, log out, change
e IE donde está (aún menos explicable) log in, change, log out, blur
.
Del mismo modo, llamar click()
a un elemento que lo proporciona llama al onclick
controlador de inmediato en todos los navegadores (¡al menos esto es consistente!).
(Estoy usando las on...
propiedades del controlador de eventos directos aquí, pero sucede lo mismo con addEventListener
y attachEvent
.)
También hay un montón de circunstancias en las que los eventos pueden activarse mientras su código está enhebrado, a pesar de que no ha hecho nada para provocarlo. Un ejemplo:
var l= document.getElementById('log');
document.getElementById('act').onclick= function() {
l.value+= 'alert in\n';
alert('alert!');
l.value+= 'alert out\n';
};
window.onresize= function() {
l.value+= 'resize\n';
};
<textarea id="log" rows="20" cols="40"></textarea>
<button id="act">alert</button>
Presiona alert
y obtendrás un cuadro de diálogo modal. No se ejecutará más script hasta que descarte ese diálogo, ¿sí? No Cambie el tamaño de la ventana principal y accederá alert in, resize, alert out
al área de texto.
Puede pensar que es imposible cambiar el tamaño de una ventana mientras está activo un cuadro de diálogo modal, pero no es así: en Linux, puede cambiar el tamaño de la ventana tanto como desee; en Windows no es tan fácil, pero puede hacerlo cambiando la resolución de la pantalla de una más grande a una más pequeña donde la ventana no se ajusta, lo que hace que cambie de tamaño.
Podrías pensar, bueno, es solo resize
(y probablemente algunos más comoscroll
) que puede activarse cuando el usuario no tiene una interacción activa con el navegador porque el script está enhebrado. Y para ventanas individuales puede que tengas razón. Pero todo se va al bote tan pronto como estás haciendo scripts de ventanas cruzadas. Para todos los navegadores que no sean Safari, que bloquea todas las ventanas / pestañas / marcos cuando alguno de ellos está ocupado, puede interactuar con un documento desde el código de otro documento, ejecutándose en un hilo de ejecución separado y haciendo que cualquier controlador de eventos relacionado fuego.
Lugares donde se pueden generar eventos que puede generar que se generen mientras el script aún está enhebrado:
cuando las ventanas emergentes modales ( alert
, confirm
, prompt
) están abiertas, pero en todos los navegadores Opera;
durante showModalDialog
en los navegadores que lo admiten;
el cuadro de diálogo "Un script en esta página puede estar ocupado ...", incluso si elige dejar que el script continúe ejecutándose, permite que eventos como cambiar el tamaño y desenfoque se activen mientras el script está en medio de un Loop ocupado, excepto en Opera.
Hace un tiempo para mí, en IE con el complemento Sun Java, llamar a cualquier método en un applet podría permitir que se desencadenaran eventos y se volviera a ingresar el script. Esto siempre fue un error sensible al tiempo, y es posible que Sun lo haya solucionado desde entonces (ciertamente espero que sí).
Probablemente más. Ha pasado un tiempo desde que probé esto y los navegadores han ganado complejidad desde entonces.
En resumen, para la mayoría de los usuarios, la mayoría de las veces, JavaScript tiene un estricto subproceso de ejecución basado en eventos. En realidad, no tiene tal cosa. No está claro cuánto de esto es simplemente un error y cuánto diseño deliberado, pero si está escribiendo aplicaciones complejas, especialmente las de ventana cruzada / scripting de marcos, hay muchas posibilidades de que pueda morderlo, y en forma intermitente, formas difíciles de depurar.
Si lo peor llega a lo peor, puede resolver los problemas de concurrencia indirectando todas las respuestas a eventos. Cuando entra un evento, suéltelo en una cola y trate la cola en orden más adelante, en una setInterval
función. Si está escribiendo un marco que pretende ser utilizado por aplicaciones complejas, hacer esto podría ser un buen movimiento. postMessage
También esperamos calmar el dolor de las secuencias de comandos de documentos cruzados en el futuro.