简体   繁体   中英

Clearing the JavaScript/jQuery Event Queue

We found, during a recent upgrade to Google Chrome (version 55+) where pointer events were introduced "with a newer standard that unifies both models: pointer events." , we need to modify how we handle events to be backwards compatible. Our application is written specifically for Chrome.

We have been experimenting this morning, trying figure out which event has been fired (based on Chrome version) so we can handle the event appropriately for all of our application's users. As a test I wrote the following:

$(document).on('mousedown touchstart pointerdown', '.foo', function(event){
    console.log( event.type + ": " +  event.which );
    switch(event.type) {
        case 'mousedown':
          console.log('moused!');
          break;
        case 'touchstart':
          console.log('touched!');
          break;
        case 'pointerdown':
          console.log('pointed');
          break;    
    };
})

In non-mobile devices both mousedown and pointerdown are registered. In mobile devices all three events are spit out to the console.

CLARIFICATION : What is needed is for none of the other events to fire once the first one is encountered and handled. In other words, if pointerdown fires, for example, then I need to prevent mousedown and touchstart from firing. Subsequent clicks should work as well, so if I get a pointerdown and click again I should get another pointerdown (or whatever event is appropriate for the browser version or device).

I expected break; would cause jQuery to leave the switch() , but that doesn't happen. So I added the .clearQueue() to each case:

$(this).clearQueue();

Once again, I expected that the event would be encountered and handled, the queue would be cleared and I wouldn't have any other events fired.

I was wrong.

I am beginning to feel like I am missing something obvious but I cannot put my finger on it. I have tried .stop() , .finish() as well as combinations of these functions in order to intercept the one function needed (based on browser version) and clear the queue so the rest will not fire.

I thought I understood the JavaScript event queue pretty well, but apparently I am wrong about that too.

Am I missing something obvious? If so, what it is?

I believe that .stop() and .finish() are related to working with an animation queue, not an event queue and .clearQueue() is not related to the event queue either:

The JQuery documentation says:

When used without an argument, .clearQueue() removes the remaining functions from fx, the standard effects queue. In this way it is similar to .stop(true). However, while the .stop() method is meant to be used only with animations, .clearQueue() can also be used to remove any function that has been added to a generic jQuery queue with the .queue() method.

But, if you have handled an event and wish to stop others from being raised, you could implement your own handled flag in a closure as a work-around:

Here's an example (executable version here ):

// These free variables will be shared in the various callback functions below
var handled = false;
var eventType = null;

$(document).on('mousedown touchstart pointerdown', '.foo', function(event){

   // If the current event hasn't been handled or if the current 
   // has been handled but the event is the same as the previous fired 
   // event, proceed:
   if(!handled || (handled && event.type === eventType)){

     // None of the events have been handled yet.
     // Determine which has fired and act appropriately:

     // Register the current event for comparison later
     eventType = event.type;

     console.log( eventType + ": " +  event.which );

     switch(eventType) {
        case 'mousedown':
          console.log('moused!');
          break;
        case 'touchstart':
          console.log('touched!');
          break;
        case 'pointerdown':
          console.log('pointed');
          break;    
     };

     // Flag that one of the events registered earlier has been handled
     handled = true;

   } else {

     // One of the earlier registered events has already been handled

     // Prevent the event from performing its native function
     // (i.e. cancel the event)
     event.preventDefault();

     // Don't allow the event to propagate
     event.stopPropagation();

   }

});

You could just return false at the end, and only the first type supported ( and first fired ) will be caught by any system.

The break works just fine but it does not affect this issue as these are different events and so fire the handler as many times as the events triggered.

 $(document).on('mousedown touchstart pointerdown', '.foo', function(event){ console.log( event.type + ": " + event.which ); switch(event.type) { case 'mousedown': console.log('moused!'); break; case 'touchstart': console.log('touched!'); break; case 'pointerdown': console.log('pointed'); break; }; // added the following line which forces any subsequent events for the same action and also stop the event from bubbling up the dom return false; })
 .foo{ padding:50px; margin:10px; border:5px double #ccc; text-align:center; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="foo">.foo box for clicking</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM