É JavaScript único segmento? Se não, como faço para obter acesso sincronizado a dados compartilhados?

StackOverflow https://stackoverflow.com/questions/161783

Pergunta

Eu tenho uma página web com DIVs com um manipulador mouseover que se destina a mostrar uma bolha de informações pop-up. Eu não quero mais do que um balão de informação a ser visível de cada vez. Mas quando o usuário move o mouse rapidamente nos dois itens, às vezes fico duas bolhas. Isso não deve acontecer, porque o código para mostrar um pop-up cancela o pop-up anterior.

Se isto fosse um sistema multi-threaded, então o problema seria óbvio: há dois tópicos tentando mostrar um pop-up, e ambos cancelar pop-ups existentes, em seguida, pop-up seus próprios pop-ups. Mas eu assumi JavaScript é sempre executado single-threaded, o que impediria isso. Estou errado? São manipuladores de eventos em execução de forma assíncrona, caso em que eu preciso sincronizado acesso aos dados compartilhados, ou eu deveria, antes, procurar erros no código da biblioteca para o cancelamento de pop-ups?

Editado para adicionar:

  • A biblioteca em questão é SIMILE Timeline e sua biblioteca Ajax;
  • O manipulador de eventos não SimileAjax.DOM.cancelEvent(domEvt) chamada, que eu assumo com base no nome cancela o borbulhar de eventos;
  • Apenas para fazer coisa é mais complicada, o que estou fazendo realmente está começando um tempo limite que se não for cancelado por uma moustout mostra o pop-up, sendo este destinado a impedir pop-ups piscando irritantemente mas irritantemente ter o efeito inverso.

Eu posso ter outro puxão para ele e ver se eu posso trabalhar para fora onde estou indo errado. : -)

Foi útil?

Solução

Sim, Javascript é single-threaded. Mesmo com navegadores como o Google Chrome, há um thread por guia.

Sem saber como você está tentando cancelar um pop-up de outra, é difícil dizer qual é a causa do seu problema.

Se seus DIVs são aninhadas uma dentro da outra, você pode ter um propagação do evento questão.

Outras dicas

Eu não sei a biblioteca que você está usando, mas se você está apenas tentando exibir uma dica de somesort de cada vez ... usar um objeto flyweight. Basicamente um flyweight é algo que é feito uma vez e usado uma e outra vez. Pense em uma única classe. Então você chamar uma classe estática que, quando invocado pela primeira vez cria automaticamente um objeto de si mesmo e armazena-o. Um isso acontece todos os estática todas as referências ao mesmo objeto e por isso você não obter várias dicas ou conflitos.

Eu uso ExtJS e eles fazem as dicas de ferramentas e caixas de mensagem como ambos os elementos flyweight. Eu estou esperando que seus enquadramentos tinha elementos flyweight, bem como, caso contrário, você só vai ter que fazer o seu próprio singleton e chamá-lo.

É rosca única em navegadores. Os manipuladores de eventos estão em execução asynchroniously em um fio, não bloqueio não allways dizer multithread. É uma das suas divs uma criança do outro? Como os eventos espalhou como bolhas na árvore dom do filho para o pai.

À semelhança do que pkaeding disse, é difícil adivinhar o problema sem ver sua marcação e roteiro; no entanto, eu me atreveria a dizer que você não está parando adequadamente a propagação do evento e / ou você não está escondendo corretamente o elemento existente. Eu não sei se você estiver usando um quadro ou não, mas aqui está uma possível solução 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));

Claro, isso pode ser generalizado mais longe, recebendo todos os elementos com, digamos, a mesma classe, interagindo através deles, e aplicando o mesmo tratamento de eventos função para cada um deles.

De qualquer maneira, espero que isso ajude.

FYI: A partir do Firefox 3 há uma mudança bastante relevante para essa discussão: threads de execução causando solicitações XMLHttpRequest síncronos se isoladas (é por isso que a interface não congelar lá durante solicitações síncronas) e a execução continua. Após a conclusão solicitação síncrona, seu fio continua bem. Eles não vão ser executadas ao mesmo tempo, no entanto contando com a suposição de que único segmento pára enquanto um procedimento síncrona (request) acontecendo não é aplicável mais.

Pode ser que a tela não é refrescante rápido o suficiente. Dependendo da biblioteca JS que você está usando, você pode ser capaz de colocar um pequeno atraso no efeito "show" pop-up.

Aqui está a versão de trabalho, mais ou menos. Ao criar itens que anexar um evento mouseover:

var self = this;
SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mouseover", function (elt, domEvt, target) {
    return self._onHover(labelElmtData.elmt, domEvt, evt);
});

Isto exige uma função que define um limite de tempo (o tempo limite pré-existentes para um item diferente é cancelado primeiro):

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);
}

Este, por sua vez, mostra a bolha se incêndios antes de ser cancelado:

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(...);
};

Isso parece funcionar agora tenho definir o tempo limite de 200 ms em vez de 100 ms. Não sei por que muito curta um tempo limite faz com que a coisa multi-bolha para acontecer, mas acho que na fila de eventos de janela ou algo ainda pode estar acontecendo enquanto os elementos recém-adicionado estão sendo definidos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top