1

This SO question & answers and DOM level3 docs states that manual events are dispatched synchronously in browsers. My question, however, relates to user-related events (real clicks), not manually triggered ones.

I created a small jsfiddle demo with a button + onclick handler, the handler does some synchronous work for 2 seconds (blocking sync wait, long enough for my eye to see what's going on). Open console to see console.logs.

The test. I click several times on the button. Although the first click (and its synchronous processing) makes the button pushed down (looks like disabled), other clicks are stored as well and processed later, asynchronously, via event loop.

The questions are:

  • when does event dispatching exactly happen? Are user events (e.g. a click) immediately pushed to JS message queue or is there an intermediate Web API queue... or in other words - which queue is this event dispatching related to?
  • what does it mean that most events (click, blur, etc - except for load) are processed synchronously in case of user events (not manual ones)? Given the test above, 1st click makes synchronous blocking callback executed (I expect nothing else to happen in the meantime) and, anyway, next clicks are stored in a queue. So storing events is parallel anyway (has to be, since main javascirpt thread is busy). Would there be any difference, theoretically, it events were processed asynchronously?

slightly modified demo shows that for a given click event, the event bubbles up and calls all related event handlers, like if event bubbling was blocking, until anything else (timeout in this example) can happen. But still it's not clear why is event dispatching synchronous.

Community
  • 1
  • 1
ducin
  • 25,621
  • 41
  • 157
  • 256
  • 1
    You have a very original implementation of "doNothing". – Tom Apr 01 '17 at 11:39
  • How many queues there are and whether you would treat them as part of the Web API or as part of the JS engine would be quite implementation-dependent. – Bergi Apr 01 '17 at 12:55
  • What do you mean by "*most events are processed synchronously in case of user events*"? **All** JS code is blocking. – Bergi Apr 01 '17 at 12:57

2 Answers2

3

It makes little sense to speak of synchronous in the context of real events, since the event queue is only processed when the current execution stack has been emptied, i.e. when there is no more synchronous code to execute. That makes the related event handlers asynchronous. This is also true for the click event handler you provided in a fiddle.

That the running code blocks any other action while it runs is no indication of how that code was triggered: asynchronously or synchronously. In both cases a busy loop for 2 seconds will be blocking for 2 seconds. When we say code runs asynchronously, it only says something of how/when the code was invoked, not on how it runs. Both synchronous and asynchronous code run in a way that they are blocking. There are some exceptions to this -- for instance web workers run in their own thread.

These "real" events are pushed on the JS message queue. Of course, they first are consumed from an OS event queue, but this is implementation specific. The important thing is that they end up in the JS message queue, together with a handler for them. The JavaScript engine only processes events when the previously running code ran to completion. By consequence these event handlers are called asynchronously.

In case of "manual" events, i.e. events triggered by code such as jQuery's .trigger() method, there is a sense in making the difference between asynchronous and synchronous. In the asynchronous case, the event would be put on the JS queue, and the current code would first run to completion. In the synchronous case, the event would not be put on the JS queue, but be executed like a function call. So the handling of the event happens as an additional call on the call stack, after which your code will resume, just like after the return from a normal function call: this is synchronous behaviour.

I ignore here the concept of micro tasks, which just means there are different priorities for executing asynchronous code.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • thanks for this answer, however it's still not clear to me. Please take a look at https://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#sync-async where it's said that `Events may be dispatched either synchronously or asynchronously.` and then here: https://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#event-types-list where you see, e.g. `click` to be `sync`. I do understand both event loop and run to completion and all the stuff, but I don't get these user events to be sync. – ducin Apr 01 '17 at 17:38
  • This shows how words *synchronous* and *asynchronous* are used differently in different contexts. The specs of the DOM (w3.org) are in principle not making assumptions about the scripting language environment built around the DOM, even though JavaScript has become the standard. Below the JavaScript layer, events could in principle be served in parallel, meaning multiple events could get into the JS message queue in unpredictable orders: that is what the DOM spec calls asynchronous. This is not how the term is used in JavaScript context: there it means: not in the same execution-stack context. – trincot Apr 01 '17 at 17:57
  • damn, so as far as I got it, `load` and `error` is quite untypical event that might be executed in a parallel context (a separate thread perhaps), whereas user events come in a single thread, hence synchronous? Strange, async is also single-threaded. – ducin Apr 01 '17 at 21:27
  • I don't see a connection with threads. The `load` event handler can only start running when any other JS code has run to completion. You can delay it with a busy loop. The meaning of asynchronous in the DOM specs is that the relative order of how events are treated is not predefined. This is unrelated to whether things run in parallel in JS: they don't. – trincot Apr 01 '17 at 21:34
0

You are referring to The JavaScript Event Loop.

To answer your question as to why dispatching, also known as processing items off the message queue, happens synchronously: JavaScript is single threaded, so there is no way 2 messages could be processing at exactly the same time.

Some extra information about the JS Event Loop:

In web browsers, messages are added any time an event occurs and there is an event listener attached to it. If there is no listener, the event is lost. So a click on an element with a click event handler will add a message--likewise with any other event.

Taken from https://developer.mozilla.org/nl/docs/Web/JavaScript/EventLoop

And here's a different take on that, taken from http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/:

JavaScript runtimes contain a message queue which stores a list of messages to be processed and their associated callback functions. These messages are queued in response to external events (such as a mouse being clicked or receiving the response to an HTTP request) given a callback function has been provided. If, for example a user were to click a button and no callback function was provided – no message would have been enqueued.

And here's the part about synchronous processing items off the message queue:

In a loop, the queue is polled for the next message (each poll referred to as a “tick”) and when a message is encountered, the callback for that message is executed.


And finally:

Would there be any difference, theoretically, it events were processed asynchronously?

Totally. If you were to expect three queue'd messages to log 1, 2 and 3 somewhere, it might log the sequence in an alternate order, like 2, 1, 3.

Tom
  • 869
  • 6
  • 25
  • Looking at your answer, I think you might not understand the question. Look at the table of browser events here and you'll see what I refer to: https://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#event-types-list. See `click` to be `sync` and `load` to be `async`. – ducin Apr 01 '17 at 17:41