In reality, browser engineers are not that stupid. Mutating the DOM will queue a layout operation, but it will not actually occur until the current JS task has finished executing. Within a JS task, such as an event handler, an XHR completion, or a setTimeout, you can mutate the DOM as many times as you like, and it will only result in a single layout pass.
(The exception is if you try to read back some measurement from the DOM, such as an element's bounding box, after mutating it. In this case, the browser does have to block while it performs layout, but that is not something can be solved with virtual DOM).
So, what is the purpose of the virtual DOM? It was invented to allow React to provide the illusion of full re-rendering. React's authors wanted to a provide an experience similar to that found on the server, where an entire HTML page is re-rendered from scratch for every load. In that way, there is never any possibility of part of the HTML becoming stale, as it all gets recreated from scratch each time.
However, the browser DOM is not designed to be blown away and recreated from scratch all the time. Nodes are expensive objects, spanning the JS and C++ worlds. Recreating the whole DOM tree each time any part of it needed updating would be too slow. So, instead, they created the virtual DOM as an intermediate data structure. React renders the virtual DOM. The virtual DOM is diffed against its previous state, and then the changes are applied to the actual DOM tree. In that way, every component's render() method can be executed, but only those parts of the DOM that have actually changed will be updated.
It's a nifty optimisation, but it's not about avoiding reflow, it's just another method of dirty checking, similar to that done in other frameworks like Angular or Ember. It's just that React chooses to diff the data structure produced by render(), rather than diffing the model data that is later used for rendering.