# Sync and async events JavaScript is a single-threaded language: only one script may execute at a given moment of time. Other activities like rendering, downloading etc may be managed by separate threads. For instance, JavaScript may execute while the browser is downloading a file, that's normal. But it is impossible that two event handlers or two `setTimeout`-scheduled function execute simultaneously. There is a [Web Workers](http://www.w3.org/TR/workers) standard which defines the support for multiple JavaScript *workers* -- subprocesses that may execute in parallel with the main code, but their abilities are limited. In the browser workers don't have access to DOM, so again we come to a single "main" JavaScript thread. ## Asynchronous events Most events are asynchronous. When an asynchronous event occurs, it gets into the *Event queue*. The browser has inner loop, called *Event Loop*, which checks the queue and processes events, executes functions etc. For example, if the browser is busy processing your `onclick`, and another event happens in the background, it is appended to the queue. When the `onclick` handler is complete, the queue is checked and the script is executed. Calls scheduled by `setTimeout/setInterval` are also passed through the event queue, so that they wait until the JavaScript engine gets free. ## Synchronous events There are events which don't use the event queue. They are called *synchronous events* and work immediately even when inside other handlers. ### DOM mutation events are synchronous. In the example below, the `onclick` handler changes an attribute of the link, which has a `DOMAttrModified(onpropertychange for IE)` listener. [summary] Synchronous mutation events are processed immediately during `onclick`. [/summary] Click the link to see: [html autorun height=auto] Click me! [/html] The `click` processing order:
  1. `alert('in onclick')` works.
  2. The attribute is changed and the DOM mutation event is processed synchronously, immediately triggering `onchange`. It outputs `alert('onpropchange')`.
  3. The rest of `onclick` executes, leading to `alert('out onclick')`.
### Nested DOM events are synchronous. [summary] There are methods which trigger an immediate event, like `elem.focus()`. These events are also processed in a synchronous manner. [/summary] Run the example below and click on the button. Notice that `onfocus` doesn't wait `onclick` to complete, it works immediately. [html autorun height=auto] [/html] In the example above, the alert order is in onclick->focus->out onclick, that clearly demonstrates the synchronous behavior. [smart] The line labelled (*) is required, because `alert(message)` focuses on the message window. When it is disposed, the browser refocuses back. So without (*) the `focus` would be triggered one extra time after the alert. [/smart] [summary] Events are also processed immediately when triggered from JavaScript by `dispatchEvent/fireEvent`. [/summary] Usually event handlers are executed one by one. So we assume that one handler finishes before the other starts. **Synchronous events break this one-by-one rule, that may can cause side-effects.** For example, the `onfocus` handler may assume that `onclick` has completed the job. There are two ways to fix it:
  1. Move `text.focus()` to the end of the `onclick` code.
  2. Wrap `text.focus()` into `setTimeout(.., 0)`: [js] button.onclick = function() { alert(1) setTimeout(function() { text.focus() }, 0) alert(2) } [/js]
The concrete way is chosen according to your architecture. ## JavaScript execution and rendering [summary]In most browsers, rendering and JavaScript use single event queue. It means that while JavaScript is running, no rendering occurs.[/summary] Check it on the demo below. **When you press `run`, the browser may halt for some time**, because it changes `div.style.backgroundColor` from #A00000 to #FFFFFF. In most browsers, you see nothing until the script finishes, or until the browser pauses it with a message that 'a script is running too long'. The exception is Opera. [html run]
[/html] In Opera, you may notice `div` is redrawn. Not every change causes a repaint, probably because of Opera internal scheduling. That's because event queues for rendering and JavaScript are different in this browser. In other browsers the repaint is postponed until the JavaScript finishes. Again, the implementation may be different, but generally **the nodes are marked as "dirty" (want to be recalculated and redrawn), and repaint is queued**. Or, the browser may just look for dirty nodes after every script and process them. [smart header="Immediate reflow"] The browser contains many optimizations to speedup rendering and painting. Generally, it tries to postpone them until the script is finished, but some actions require nodes to be rerendered immediately. For example: [js] elem.innerHTML = 'new content' alert(elem.offsetHeight) // <-- rerenders elem to get offsetHeight [/js] In the case above, the browser has to perform relayouting to get the height. But it doesn't have to repaint `elem` on the screen. Sometimes other dependant nodes may get involved into calculations. This process is called *reflow* and may consume lots of resources if script causes it often. Surely, there's much more to talk about rendering. It will be covered by a separate article [todo]. [/smart] ## Modal and synchronous calls [summary]Modal and synchronous calls like `alert` pause the JavaScript thread. That causes related activities to freeze. [/summary] The example below demonstrates it.
  1. Press "Run". The `setInterval`-based animation will start and and `alert` button will appear.
  2. Press the button, note that the animation stops.
[html run height=60]
[/html] When you press `alert('Hello!')`, the `alert` blocks JavaScript execution and blocks the whole UI thread. That's how `alert`, `confirm` and `prompt` work. And there is only one thread. So, **`setTimeout/setInterval` can't execute while the thread is blocked.** ### Opera: `iframes` exception. [summary]Usually, `iframes` run in the same thread with the page. [/summary] But there is an exception called Opera. **Run the example above in Opera** and press alert in the main window. The iframe animation will continue! That's because the example is actually running in an iframe. Other browsers use single thread for whole tab, so the iframe animation is paused there. ## Script taking too long and heavy jobs JavaScript can be heavy. In this case, the browser may hangup for a moment or come with a warning "Script is taking too long". We'd want to evade that. It can be done by split the job into parts which get scheduled after each other. Then there is a "free time" for the browser to respond between parts. It is can render and react on other events. Both the visitor and the browser are happy. The background color in the example below is changed once per tick. So the browser has the time to render it, and there are no hangups. Changes are applied incrementally. Press the run button on the example to start. [html run]
[/html] The internal order:
  1. `setTimeout` appends the `func` call to the event queue.
  2. The new call is scheduled on the next tick.
  3. The func executes and changes the `div` which appends a repaint request to the queue.
  4. The function finishes. The browser takes the next event from the queue which is repaint and executes it. Then it waits the next tick to execute one more `func` call (see step 2).
  5. Repeated until `stop()`
A delay may be increased from 0 to 100 ms, depending on your needs. The longer delay leads to less CPU load. [smart header="Evade the 'script is running for too long' warning"] As an important side-effect, splitting the long job into parts which are executed by `setTimeout` helps to fix browser hangups and evade warnings. For example, modern syntax highlighters employ such technique. When a visitor opens a large text, they highlight a part of it then call something like `setTimeout(highlightNext, 50)` which highlights the next part etc. It would hangup otherwise, because the syntax highlighting takes time. [/smart] ## Summary Most browsers use single thread for UI and JavaScript, which is blocked by synchronous calls. So, JavaScript execution blocks the rendering. Events are processed asynchronously with the exception of DOM events. The `setTimeout(..,0)` trick is very useful. It allows to: Opera is special in many places when it comes to timeouts and threading.