recorrer - ¿JavaScript tiene un solo hilo? Si no, ¿cómo obtengo acceso sincronizado a los datos compartidos?
recorrer array de objetos javascript (7)
Tengo una página web con DIV
s con un manejador de mouseover
que está destinado a mostrar una burbuja de información emergente. No quiero que se vea más de una burbuja de información a la vez. Pero cuando el usuario mueve el mouse rápidamente sobre dos elementos, a veces tengo dos burbujas. Esto no debería suceder, porque el código para mostrar una ventana emergente cancela la ventana emergente anterior.
Si se tratara de un sistema de subprocesos múltiples, el problema sería obvio: hay dos subprocesos que intentan mostrar una ventana emergente, y ambos cancelan las ventanas emergentes existentes y luego muestran sus propias ventanas emergentes. Pero asumí que JavaScript siempre se ejecuta con un único subproceso, lo que evitaría esto. ¿Me equivoco? ¿Los manejadores de eventos se ejecutan de forma asíncrona, en cuyo caso necesito acceso sincronizado a los datos compartidos, o debería buscar errores en el código de la biblioteca para cancelar las ventanas emergentes?
Editado para agregar:
- La biblioteca en cuestión es SIMILE Timeline y su biblioteca Ajax;
- El controlador de eventos llama a
SimileAjax.DOM.cancelEvent(domEvt)
, que supongo que en función del nombre cancela el burbujeo de eventos; - Solo para hacer las cosas más complicadas, lo que estoy haciendo en realidad es comenzar un tiempo de espera que si no se cancela mediante un
moustout
muestra lamoustout
emergente, con la intención de evitar que las ventanas emergentes parpadeen molesta pero molestamente teniendo el efecto inverso.
Tendré otro ataque y veré si puedo averiguar dónde me estoy equivocando. :-)
Aquí está la versión de trabajo, más o menos. Al crear elementos, adjuntamos un evento mouseover
:
var self = this;
SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mouseover", function (elt, domEvt, target) {
return self._onHover(labelElmtData.elmt, domEvt, evt);
});
Esto llama a una función que establece un tiempo de espera (timeouts preexistentes para un elemento diferente se cancela primero):
MyPlan.EventPainter.prototype._onHover = function(target, domEvt, evt) {
... calculate x and y ...
domEvt.cancelBubble = true;
SimileAjax.DOM.cancelEvent(domEvt);
this._futureShowBubble(x, y, evt);
return false;
}
MyPlan.EventPainter.prototype._futureShowBubble = function (x, y, evt) {
if (this._futurePopup) {
if (evt.getID() == this._futurePopup.evt.getID()) {
return;
} else {
/* We had queued a different event''s pop-up; this must now be cancelled. */
window.clearTimeout(this._futurePopup.timeoutID);
}
}
this._futurePopup = {
x: x,
y: y,
evt: evt
};
var self = this;
this._futurePopup.timeoutID = window.setTimeout(function () {
self._onTimeout();
}, this._popupTimeout);
}
Esto a su vez muestra la burbuja si se dispara antes de ser cancelada:
MyPlan.EventPainter.prototype._onTimeout = function () {
this._showBubble(this._futurePopup.x, this._futurePopup.y, this._futurePopup.evt);
};
MyPlan.EventPainter.prototype._showBubble = function(x, y, evt) {
if (this._futurePopup) {
window.clearTimeout(this._futurePopup.timeoutID);
this._futurePopup = null;
}
...
SimileAjax.WindowManager.cancelPopups();
SimileAjax.Graphics.createBubbleForContentAndPoint(...);
};
Esto parece funcionar ahora. Configuré el tiempo de espera en 200 ms en lugar de 100 ms. No estoy seguro de por qué un tiempo de espera tan corto hace que ocurra lo que ocurre con las múltiples burbujas, pero supongo que la espera de los eventos de la ventana o algo así podría estar ocurriendo mientras se están diseñando los elementos recién agregados.
De forma similar a lo que dice pkaeding, es difícil adivinar el problema sin ver tu marcado y script; sin embargo, me atrevería a decir que no está deteniendo correctamente la propagación del evento y / o no está ocultando correctamente el elemento existente. No sé si estás usando un framework o no, pero aquí hay una posible solución usando Prototype:
// maintain a reference to the active div bubble
this.oActiveDivBubble = null;
// event handler for the first div
$(''exampleDiv1'').observe(''mouseover'', function(evt) {
evt.stop();
if(this.oActiveDivBubble ) {
this.oActiveDivBubble .hide();
}
this.oActiveDivBubble = $(''exampleDiv1Bubble'');
this.oActiveDivBubble .show();
}.bind(this));
// event handler for the second div
$(''exampleDiv2'').observe(''mouseover''), function(evt) {
evt.stop();
if(this.oActiveDivBubble) {
this.oActiveDivBubble.hide();
}
this.oActiveDivBubble = $(''exampleDiv2Bubble'');
this.oActiveDivBubble .show();
}.bind(this));
Por supuesto, esto podría generalizarse más al obtener todos los elementos con, digamos, la misma clase, iterar a través de ellos y aplicar la misma función de manejo de eventos a cada uno de ellos.
De cualquier manera, con suerte esto ayuda.
Es de un solo hilo en los navegadores. Los controladores de eventos se ejecutan de forma asincrónica en un hilo, no bloquear no siempre significa multiproceso. ¿Es uno de sus divs un hijo del otro? Porque los eventos se extienden como burbujas en el árbol dom de niño a padre.
FYI: A partir de Firefox 3 hay un cambio bastante relevante para esta discusión: los hilos de ejecución causan que las solicitudes sincrónicas XMLHttpRequest se desprendan (esta es la razón por la cual la interfaz no se congela allí durante las solicitudes sincrónicas) y la ejecución continúa. Tras completar la solicitud sincrónica, su hilo también continúa. No se ejecutarán al mismo tiempo, sin embargo, se basa en la suposición de que un solo subproceso se detiene mientras que un procedimiento síncrono (solicitud) no se aplica más.
Podría ser que la pantalla no se esté refrescando lo suficientemente rápido. Dependiendo de la biblioteca JS que esté utilizando, es posible que pueda poner un pequeño retraso en el efecto emergente de "mostrar".
Sí, Javascript tiene un único hilo. Incluso con navegadores como Google Chrome, hay un hilo por pestaña.
Sin saber cómo está intentando cancelar una ventana emergente de otra, es difícil decir cuál es la causa de su problema.
Si sus DIV están anidados entre sí, puede tener un problema de propagación de eventos .
No conozco la biblioteca que está utilizando, pero si solo está tratando de mostrar una información sobre herramientas de algún tipo a la vez ... use un objeto flyweight. Básicamente, un flyweight es algo que se fabrica una vez y se usa una y otra vez. Piensa en una clase singleton. Entonces llama a una clase estáticamente que, cuando se invoca por primera vez, crea automáticamente un objeto y lo almacena. Uno esto sucede cada estático todas las referencias del mismo objeto y debido a esto no se obtiene múltiples información sobre herramientas o conflictos.
Yo uso ExtJS y ellos hacen tooltips, y cuadros de mensaje como ambos elementos flyweight. Espero que tus frameworks también tengan elementos flyweight, de lo contrario solo tendrás que crear tu propio singleton y llamarlo.