Why is there a difference in the task/microtask execution order when a button is programmatically clicked vs DOM clicked? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) Data science time! April 2019 and salary with experience Should we burninate the [wrap] tag? The Ask Question Wizard is Live!Initial run through of a JavaScript fileHow are the Event Loop, Callback Queue, and Javascript’s single thread connected?is angular's promises misleading in that they are not always called asynchronouslyJavaScript event loop: why is my click function executed before other tasks in the queue?When will requestAnimationFrame be executed?Node.js event loop understanding (with a diagram)What is the relationship between event loop and PromiseWhat is the difference between physical and programmatically click in browserevent loop prefers microtask queue over callback queue?JavaScript functions put in event loop

Apollo command module space walk?

2001: A Space Odyssey's use of the song "Daisy Bell" (Bicycle Built for Two); life imitates art or vice-versa?

What is the meaning of the new sigil in Game of Thrones Season 8 intro?

Why did the IBM 650 use bi-quinary?

Why was the term "discrete" used in discrete logarithm?

What exactly is a "Meth" in Altered Carbon?

How to find out what spells would be useless to a blind NPC spellcaster?

How to override model in magento2?

How widely used is the term Treppenwitz? Is it something that most Germans know?

Is it true that "carbohydrates are of no use for the basal metabolic need"?

What is known about the Ubaid lizard-people figurines?

How to tell that you are a giant?

Single word antonym of "flightless"

Identifying polygons that intersect with another layer using QGIS?

What causes the vertical darker bands in my photo?

When were vectors invented?

English words in a non-english sci-fi novel

Identify plant with long narrow paired leaves and reddish stems

51k Euros annually for a family of 4 in Berlin: Is it enough?

How to find all the available tools in mac terminal?

Why are both D and D# fitting into my E minor key?

Fundamental Solution of the Pell Equation

Book where humans were engineered with genes from animal species to survive hostile planets

Okay to merge included columns on otherwise identical indexes?



Why is there a difference in the task/microtask execution order when a button is programmatically clicked vs DOM clicked?



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)
Data science time! April 2019 and salary with experience
Should we burninate the [wrap] tag?
The Ask Question Wizard is Live!Initial run through of a JavaScript fileHow are the Event Loop, Callback Queue, and Javascript’s single thread connected?is angular's promises misleading in that they are not always called asynchronouslyJavaScript event loop: why is my click function executed before other tasks in the queue?When will requestAnimationFrame be executed?Node.js event loop understanding (with a diagram)What is the relationship between event loop and PromiseWhat is the difference between physical and programmatically click in browserevent loop prefers microtask queue over callback queue?JavaScript functions put in event loop



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








9















There seems to a difference in the execution order of the microtask/task queues when a button is clicked in the DOM, vs it being programatically clicked.






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

<button id='btn'>Click me !</button>





My understanding is that when the callstack is empty, the event loop will take callbacks from the microtask queue to place on the callstack. When both the callstack and microtask queue are empty, the event loop starts taking callbacks from the task queue.



When the button with the id btn is clicked, both "click" event listeners are placed on the task queue in order they are declared in.



// representing the callstack and task queues as arrays
callstack: []
microtask queue: []
task queue: ["click-1", "click-2"]


The event loop places the "click-1" callback on the callstack. It has a promise that immediately resolves, placing the "resolved-1" callback on the microtask queue.



callstack: ["click-1"]
microtask queue: ["resolved-1"]
task queue: ["click-2"]


The "click-1" callback executes its console.log, and completes. Now there's something on the microtask queue, so the event loop takes the "resolved-1" callback and places it on the callstack.



callstack: ["resolved-1"]
microtask queue: []
task queue: ["click-2"]


"resolved-1" callback is executed. Now both the callstack and microtask queue and are empty.



callstack: []
microtask queue: []
task queue: ["click-2"]


The event loop then "looks" at the task queue once again, and the cycle repeats.



// "click-2" is placed on the callstack
callstack: ["click-2"]
microtask queue: []
task queue: []

// Immediately resolved promise puts "resolved-2" in the microtask queue
callstack: ["click-2"]
microtask queue: ["resolved-2"]
task queue: []

// "click-2" completes ...
callstack: []
microtask queue: ["resolved-2"]
task queue: []

// "resolved-2" executes ...
callstack: ["resolved-2"]
microtask queue: []
task queue: []

// and completes
callstack: []
microtask queue: []
task queue: []



This would explain this output from the code snippet above



"hello click1"
"resolved click1"
"hello click2"
"resolved click2"


I would expect it to be the same then I programatically click the button with btn.click().






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

btn.click()

<button id='btn'>Click me!</button>





However, the output is different.



"hello click1"
"hello click2"
"resolved click1"
"resolved click2"


Why is there a difference in the execution order when button is programatically clicked ?










share|improve this question



















  • 2





    OMG, I'm giving a talk about this in fullstack london :D button.click() doesn't actually click a button

    – Benjamin Gruenbaum
    15 hours ago


















9















There seems to a difference in the execution order of the microtask/task queues when a button is clicked in the DOM, vs it being programatically clicked.






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

<button id='btn'>Click me !</button>





My understanding is that when the callstack is empty, the event loop will take callbacks from the microtask queue to place on the callstack. When both the callstack and microtask queue are empty, the event loop starts taking callbacks from the task queue.



When the button with the id btn is clicked, both "click" event listeners are placed on the task queue in order they are declared in.



// representing the callstack and task queues as arrays
callstack: []
microtask queue: []
task queue: ["click-1", "click-2"]


The event loop places the "click-1" callback on the callstack. It has a promise that immediately resolves, placing the "resolved-1" callback on the microtask queue.



callstack: ["click-1"]
microtask queue: ["resolved-1"]
task queue: ["click-2"]


The "click-1" callback executes its console.log, and completes. Now there's something on the microtask queue, so the event loop takes the "resolved-1" callback and places it on the callstack.



callstack: ["resolved-1"]
microtask queue: []
task queue: ["click-2"]


"resolved-1" callback is executed. Now both the callstack and microtask queue and are empty.



callstack: []
microtask queue: []
task queue: ["click-2"]


The event loop then "looks" at the task queue once again, and the cycle repeats.



// "click-2" is placed on the callstack
callstack: ["click-2"]
microtask queue: []
task queue: []

// Immediately resolved promise puts "resolved-2" in the microtask queue
callstack: ["click-2"]
microtask queue: ["resolved-2"]
task queue: []

// "click-2" completes ...
callstack: []
microtask queue: ["resolved-2"]
task queue: []

// "resolved-2" executes ...
callstack: ["resolved-2"]
microtask queue: []
task queue: []

// and completes
callstack: []
microtask queue: []
task queue: []



This would explain this output from the code snippet above



"hello click1"
"resolved click1"
"hello click2"
"resolved click2"


I would expect it to be the same then I programatically click the button with btn.click().






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

btn.click()

<button id='btn'>Click me!</button>





However, the output is different.



"hello click1"
"hello click2"
"resolved click1"
"resolved click2"


Why is there a difference in the execution order when button is programatically clicked ?










share|improve this question



















  • 2





    OMG, I'm giving a talk about this in fullstack london :D button.click() doesn't actually click a button

    – Benjamin Gruenbaum
    15 hours ago














9












9








9








There seems to a difference in the execution order of the microtask/task queues when a button is clicked in the DOM, vs it being programatically clicked.






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

<button id='btn'>Click me !</button>





My understanding is that when the callstack is empty, the event loop will take callbacks from the microtask queue to place on the callstack. When both the callstack and microtask queue are empty, the event loop starts taking callbacks from the task queue.



When the button with the id btn is clicked, both "click" event listeners are placed on the task queue in order they are declared in.



// representing the callstack and task queues as arrays
callstack: []
microtask queue: []
task queue: ["click-1", "click-2"]


The event loop places the "click-1" callback on the callstack. It has a promise that immediately resolves, placing the "resolved-1" callback on the microtask queue.



callstack: ["click-1"]
microtask queue: ["resolved-1"]
task queue: ["click-2"]


The "click-1" callback executes its console.log, and completes. Now there's something on the microtask queue, so the event loop takes the "resolved-1" callback and places it on the callstack.



callstack: ["resolved-1"]
microtask queue: []
task queue: ["click-2"]


"resolved-1" callback is executed. Now both the callstack and microtask queue and are empty.



callstack: []
microtask queue: []
task queue: ["click-2"]


The event loop then "looks" at the task queue once again, and the cycle repeats.



// "click-2" is placed on the callstack
callstack: ["click-2"]
microtask queue: []
task queue: []

// Immediately resolved promise puts "resolved-2" in the microtask queue
callstack: ["click-2"]
microtask queue: ["resolved-2"]
task queue: []

// "click-2" completes ...
callstack: []
microtask queue: ["resolved-2"]
task queue: []

// "resolved-2" executes ...
callstack: ["resolved-2"]
microtask queue: []
task queue: []

// and completes
callstack: []
microtask queue: []
task queue: []



This would explain this output from the code snippet above



"hello click1"
"resolved click1"
"hello click2"
"resolved click2"


I would expect it to be the same then I programatically click the button with btn.click().






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

btn.click()

<button id='btn'>Click me!</button>





However, the output is different.



"hello click1"
"hello click2"
"resolved click1"
"resolved click2"


Why is there a difference in the execution order when button is programatically clicked ?










share|improve this question
















There seems to a difference in the execution order of the microtask/task queues when a button is clicked in the DOM, vs it being programatically clicked.






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

<button id='btn'>Click me !</button>





My understanding is that when the callstack is empty, the event loop will take callbacks from the microtask queue to place on the callstack. When both the callstack and microtask queue are empty, the event loop starts taking callbacks from the task queue.



When the button with the id btn is clicked, both "click" event listeners are placed on the task queue in order they are declared in.



// representing the callstack and task queues as arrays
callstack: []
microtask queue: []
task queue: ["click-1", "click-2"]


The event loop places the "click-1" callback on the callstack. It has a promise that immediately resolves, placing the "resolved-1" callback on the microtask queue.



callstack: ["click-1"]
microtask queue: ["resolved-1"]
task queue: ["click-2"]


The "click-1" callback executes its console.log, and completes. Now there's something on the microtask queue, so the event loop takes the "resolved-1" callback and places it on the callstack.



callstack: ["resolved-1"]
microtask queue: []
task queue: ["click-2"]


"resolved-1" callback is executed. Now both the callstack and microtask queue and are empty.



callstack: []
microtask queue: []
task queue: ["click-2"]


The event loop then "looks" at the task queue once again, and the cycle repeats.



// "click-2" is placed on the callstack
callstack: ["click-2"]
microtask queue: []
task queue: []

// Immediately resolved promise puts "resolved-2" in the microtask queue
callstack: ["click-2"]
microtask queue: ["resolved-2"]
task queue: []

// "click-2" completes ...
callstack: []
microtask queue: ["resolved-2"]
task queue: []

// "resolved-2" executes ...
callstack: ["resolved-2"]
microtask queue: []
task queue: []

// and completes
callstack: []
microtask queue: []
task queue: []



This would explain this output from the code snippet above



"hello click1"
"resolved click1"
"hello click2"
"resolved click2"


I would expect it to be the same then I programatically click the button with btn.click().






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

btn.click()

<button id='btn'>Click me!</button>





However, the output is different.



"hello click1"
"hello click2"
"resolved click1"
"resolved click2"


Why is there a difference in the execution order when button is programatically clicked ?






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

<button id='btn'>Click me !</button>





const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

<button id='btn'>Click me !</button>





const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

btn.click()

<button id='btn'>Click me!</button>





const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);

btn.click()

<button id='btn'>Click me!</button>






javascript






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 15 hours ago







peonicles

















asked 15 hours ago









peoniclespeonicles

580921




580921







  • 2





    OMG, I'm giving a talk about this in fullstack london :D button.click() doesn't actually click a button

    – Benjamin Gruenbaum
    15 hours ago













  • 2





    OMG, I'm giving a talk about this in fullstack london :D button.click() doesn't actually click a button

    – Benjamin Gruenbaum
    15 hours ago








2




2





OMG, I'm giving a talk about this in fullstack london :D button.click() doesn't actually click a button

– Benjamin Gruenbaum
15 hours ago






OMG, I'm giving a talk about this in fullstack london :D button.click() doesn't actually click a button

– Benjamin Gruenbaum
15 hours ago













3 Answers
3






active

oldest

votes


















6














Fascinating question.



First, the easy part: When you call click, it's a synchronous call triggering all of the event handlers on the button. You can see that if you add logging around the call:






const btn = document.querySelector('#btn');

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-1'); );
console.log('click-1');
);

btn.addEventListener("click", function()
Promise.resolve().then(function() console.log('resolved-2'); );
console.log('click-2');
);


document.getElementById("btn-simulate").addEventListener("click", function()
console.log("About to call click");
btn.click();
console.log("Done calling click");
);

<input type="button" id="btn" value="Direct Click">
<input type="button" id="btn-simulate" value="Call click()">





Since the handlers are run synchronously, microtasks are processed only after both handlers have finished. Processing them sooner would require breaking JavaScript's run-to-completion semantics.



In contrast, when the event is dispatched via the DOM, it's more interesting: Each handler is invoked. Invoking a handler includes cleaning up after running script, which includes doing a microtask checkpoint, running any pending microtasks. So microtasks scheduled by the handler that was invoked get run before the next handler gets run.



That's "why" they're different in one sense: Because the handler callbacks are called synchronously, in order, when you use click(), and so there's no opportunity to process microtasks between them.



Looking at "why" slightly differently: Why are the handlers called synchronously when you use click()? Primarily because of history, that's what early browsers did and so it can't be changed. But they're also synchronous if you use dispatchEvent:



const e = new MouseEvent("click");
btn.dispatchEvent(e);


In that case, the handlers are still run synchronously, because the code using it might need to look at e to see if the default action was prevented or similar. (It could have been defined differently, providing a callback or some such for when the event was done being dispatched, but it wasn't. I'd guess that it wasn't for either simplicity, compatibility with click, or both.)






share|improve this answer

























  • To check my understanding. When I do .click(), it's as if I'm executing handler1(); handler2(); to completion, after which microtasks are executed ?

    – peonicles
    15 hours ago






  • 2





    Actually there are subtle differences between click and dispatchEvent (we run into those all the time when playing things at Testim and had to normalize). I'll see if I can dig up the chromium code later today to discuss. Also - note that .click is special and the answer to "why does it work this way" is "legacy, and because trusted events weren't always a thing" - .click is very special in the DOM (not to mention DOMActivate fun).

    – Benjamin Gruenbaum
    14 hours ago






  • 1





    I'll make a gist, but as a simple one every .click() reports (anonymously) to home base (Google) in Chrome (via RuntimeCallStatsCounter) in Chromium and dispatchEvent doesn't :D

    – Benjamin Gruenbaum
    14 hours ago






  • 1





    @BenjaminGruenbaum - Ugh, not a big fan of even anonymous phone-homes like that. Thanks! Wish I were going to FullStack London to see your talk, but I doubt I will be... :-| Maybe, though...

    – T.J. Crowder
    14 hours ago







  • 1





    Actually, not a lot of code, here: gist.github.com/benjamingr/915d0423f8bcf9db6d9fd852c28174ab

    – Benjamin Gruenbaum
    14 hours ago


















3














dispatchEvent




Unlike "native" events, which are fired by the DOM and invoke event
handlers asynchronously via the event loop, dispatchEvent invokes
event handlers synchronously.
All applicable event handlers will
execute and return before the code continues on after the call to
dispatchEvent.



dispatchEvent is the last step of the create-init-dispatch process,
which is used for dispatching events into the implementation's event
model. The event can be created using Event constructor.







share|improve this answer























  • That's half of it. :-)

    – T.J. Crowder
    15 hours ago






  • 1





    @T.J.Crowder I'm your fan :D I love your comprehensive answers

    – ponury-kostek
    15 hours ago



















1














So, Chrome answer just because it's interesting (see T.J Crowder's excellent answer for the general DOM answer).



btn.click();


Calls into HTMLElement::click() in C++ which is the counterpart of the DOMElement:



void HTMLElement::click() 
DispatchSimulatedClick(nullptr, kSendNoEvents,
SimulatedClickCreationScope::kFromScript);



Which basically does some work around dispatchMouseEvent and deals with edge cases:



void EventDispatcher::DispatchSimulatedClick(
Node& node,
Event* underlying_event,
SimulatedClickMouseEventOptions mouse_event_options,
SimulatedClickCreationScope creation_scope)
// This persistent vector doesn't cause leaks, because added Nodes are removed
// before dispatchSimulatedClick() returns. This vector is here just to
// prevent the code from running into an infinite recursion of
// dispatchSimulatedClick().
DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<Member<Node>>>,
nodes_dispatching_simulated_clicks,
(MakeGarbageCollected<HeapHashSet<Member<Node>>>()));

if (IsDisabledFormControl(&node))
return;

if (nodes_dispatching_simulated_clicks->Contains(&node))
return;

nodes_dispatching_simulated_clicks->insert(&node);

if (mouse_event_options == kSendMouseOverUpDownEvents)
EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseover,
node.GetDocument().domWindow(),
underlying_event, creation_scope))
.Dispatch();

if (mouse_event_options != kSendNoEvents)
EventDispatcher(node, *MouseEvent::Create(event_type_names::kMousedown,
node.GetDocument().domWindow(),
underlying_event, creation_scope))
.Dispatch();
node.SetActive(true);
EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseup,
node.GetDocument().domWindow(),
underlying_event, creation_scope))
.Dispatch();

// Some elements (e.g. the color picker) may set active state to true before
// calling this method and expect the state to be reset during the call.
node.SetActive(false);

// always send click
EventDispatcher(node, *MouseEvent::Create(event_type_names::kClick,
node.GetDocument().domWindow(),
underlying_event, creation_scope))
.Dispatch();

nodes_dispatching_simulated_clicks->erase(&node);



It is entirely synchronous by design to make testing simple as well as for legacy reasons (think DOMActivate weird things).



This is just a direct call, there is no task scheduling involved. EventTarget in general is a synchronous interface that does not defer things and it predates microtick semantics and promises :]






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55709512%2fwhy-is-there-a-difference-in-the-task-microtask-execution-order-when-a-button-is%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    6














    Fascinating question.



    First, the easy part: When you call click, it's a synchronous call triggering all of the event handlers on the button. You can see that if you add logging around the call:






    const btn = document.querySelector('#btn');

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-1'); );
    console.log('click-1');
    );

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-2'); );
    console.log('click-2');
    );


    document.getElementById("btn-simulate").addEventListener("click", function()
    console.log("About to call click");
    btn.click();
    console.log("Done calling click");
    );

    <input type="button" id="btn" value="Direct Click">
    <input type="button" id="btn-simulate" value="Call click()">





    Since the handlers are run synchronously, microtasks are processed only after both handlers have finished. Processing them sooner would require breaking JavaScript's run-to-completion semantics.



    In contrast, when the event is dispatched via the DOM, it's more interesting: Each handler is invoked. Invoking a handler includes cleaning up after running script, which includes doing a microtask checkpoint, running any pending microtasks. So microtasks scheduled by the handler that was invoked get run before the next handler gets run.



    That's "why" they're different in one sense: Because the handler callbacks are called synchronously, in order, when you use click(), and so there's no opportunity to process microtasks between them.



    Looking at "why" slightly differently: Why are the handlers called synchronously when you use click()? Primarily because of history, that's what early browsers did and so it can't be changed. But they're also synchronous if you use dispatchEvent:



    const e = new MouseEvent("click");
    btn.dispatchEvent(e);


    In that case, the handlers are still run synchronously, because the code using it might need to look at e to see if the default action was prevented or similar. (It could have been defined differently, providing a callback or some such for when the event was done being dispatched, but it wasn't. I'd guess that it wasn't for either simplicity, compatibility with click, or both.)






    share|improve this answer

























    • To check my understanding. When I do .click(), it's as if I'm executing handler1(); handler2(); to completion, after which microtasks are executed ?

      – peonicles
      15 hours ago






    • 2





      Actually there are subtle differences between click and dispatchEvent (we run into those all the time when playing things at Testim and had to normalize). I'll see if I can dig up the chromium code later today to discuss. Also - note that .click is special and the answer to "why does it work this way" is "legacy, and because trusted events weren't always a thing" - .click is very special in the DOM (not to mention DOMActivate fun).

      – Benjamin Gruenbaum
      14 hours ago






    • 1





      I'll make a gist, but as a simple one every .click() reports (anonymously) to home base (Google) in Chrome (via RuntimeCallStatsCounter) in Chromium and dispatchEvent doesn't :D

      – Benjamin Gruenbaum
      14 hours ago






    • 1





      @BenjaminGruenbaum - Ugh, not a big fan of even anonymous phone-homes like that. Thanks! Wish I were going to FullStack London to see your talk, but I doubt I will be... :-| Maybe, though...

      – T.J. Crowder
      14 hours ago







    • 1





      Actually, not a lot of code, here: gist.github.com/benjamingr/915d0423f8bcf9db6d9fd852c28174ab

      – Benjamin Gruenbaum
      14 hours ago















    6














    Fascinating question.



    First, the easy part: When you call click, it's a synchronous call triggering all of the event handlers on the button. You can see that if you add logging around the call:






    const btn = document.querySelector('#btn');

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-1'); );
    console.log('click-1');
    );

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-2'); );
    console.log('click-2');
    );


    document.getElementById("btn-simulate").addEventListener("click", function()
    console.log("About to call click");
    btn.click();
    console.log("Done calling click");
    );

    <input type="button" id="btn" value="Direct Click">
    <input type="button" id="btn-simulate" value="Call click()">





    Since the handlers are run synchronously, microtasks are processed only after both handlers have finished. Processing them sooner would require breaking JavaScript's run-to-completion semantics.



    In contrast, when the event is dispatched via the DOM, it's more interesting: Each handler is invoked. Invoking a handler includes cleaning up after running script, which includes doing a microtask checkpoint, running any pending microtasks. So microtasks scheduled by the handler that was invoked get run before the next handler gets run.



    That's "why" they're different in one sense: Because the handler callbacks are called synchronously, in order, when you use click(), and so there's no opportunity to process microtasks between them.



    Looking at "why" slightly differently: Why are the handlers called synchronously when you use click()? Primarily because of history, that's what early browsers did and so it can't be changed. But they're also synchronous if you use dispatchEvent:



    const e = new MouseEvent("click");
    btn.dispatchEvent(e);


    In that case, the handlers are still run synchronously, because the code using it might need to look at e to see if the default action was prevented or similar. (It could have been defined differently, providing a callback or some such for when the event was done being dispatched, but it wasn't. I'd guess that it wasn't for either simplicity, compatibility with click, or both.)






    share|improve this answer

























    • To check my understanding. When I do .click(), it's as if I'm executing handler1(); handler2(); to completion, after which microtasks are executed ?

      – peonicles
      15 hours ago






    • 2





      Actually there are subtle differences between click and dispatchEvent (we run into those all the time when playing things at Testim and had to normalize). I'll see if I can dig up the chromium code later today to discuss. Also - note that .click is special and the answer to "why does it work this way" is "legacy, and because trusted events weren't always a thing" - .click is very special in the DOM (not to mention DOMActivate fun).

      – Benjamin Gruenbaum
      14 hours ago






    • 1





      I'll make a gist, but as a simple one every .click() reports (anonymously) to home base (Google) in Chrome (via RuntimeCallStatsCounter) in Chromium and dispatchEvent doesn't :D

      – Benjamin Gruenbaum
      14 hours ago






    • 1





      @BenjaminGruenbaum - Ugh, not a big fan of even anonymous phone-homes like that. Thanks! Wish I were going to FullStack London to see your talk, but I doubt I will be... :-| Maybe, though...

      – T.J. Crowder
      14 hours ago







    • 1





      Actually, not a lot of code, here: gist.github.com/benjamingr/915d0423f8bcf9db6d9fd852c28174ab

      – Benjamin Gruenbaum
      14 hours ago













    6












    6








    6







    Fascinating question.



    First, the easy part: When you call click, it's a synchronous call triggering all of the event handlers on the button. You can see that if you add logging around the call:






    const btn = document.querySelector('#btn');

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-1'); );
    console.log('click-1');
    );

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-2'); );
    console.log('click-2');
    );


    document.getElementById("btn-simulate").addEventListener("click", function()
    console.log("About to call click");
    btn.click();
    console.log("Done calling click");
    );

    <input type="button" id="btn" value="Direct Click">
    <input type="button" id="btn-simulate" value="Call click()">





    Since the handlers are run synchronously, microtasks are processed only after both handlers have finished. Processing them sooner would require breaking JavaScript's run-to-completion semantics.



    In contrast, when the event is dispatched via the DOM, it's more interesting: Each handler is invoked. Invoking a handler includes cleaning up after running script, which includes doing a microtask checkpoint, running any pending microtasks. So microtasks scheduled by the handler that was invoked get run before the next handler gets run.



    That's "why" they're different in one sense: Because the handler callbacks are called synchronously, in order, when you use click(), and so there's no opportunity to process microtasks between them.



    Looking at "why" slightly differently: Why are the handlers called synchronously when you use click()? Primarily because of history, that's what early browsers did and so it can't be changed. But they're also synchronous if you use dispatchEvent:



    const e = new MouseEvent("click");
    btn.dispatchEvent(e);


    In that case, the handlers are still run synchronously, because the code using it might need to look at e to see if the default action was prevented or similar. (It could have been defined differently, providing a callback or some such for when the event was done being dispatched, but it wasn't. I'd guess that it wasn't for either simplicity, compatibility with click, or both.)






    share|improve this answer















    Fascinating question.



    First, the easy part: When you call click, it's a synchronous call triggering all of the event handlers on the button. You can see that if you add logging around the call:






    const btn = document.querySelector('#btn');

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-1'); );
    console.log('click-1');
    );

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-2'); );
    console.log('click-2');
    );


    document.getElementById("btn-simulate").addEventListener("click", function()
    console.log("About to call click");
    btn.click();
    console.log("Done calling click");
    );

    <input type="button" id="btn" value="Direct Click">
    <input type="button" id="btn-simulate" value="Call click()">





    Since the handlers are run synchronously, microtasks are processed only after both handlers have finished. Processing them sooner would require breaking JavaScript's run-to-completion semantics.



    In contrast, when the event is dispatched via the DOM, it's more interesting: Each handler is invoked. Invoking a handler includes cleaning up after running script, which includes doing a microtask checkpoint, running any pending microtasks. So microtasks scheduled by the handler that was invoked get run before the next handler gets run.



    That's "why" they're different in one sense: Because the handler callbacks are called synchronously, in order, when you use click(), and so there's no opportunity to process microtasks between them.



    Looking at "why" slightly differently: Why are the handlers called synchronously when you use click()? Primarily because of history, that's what early browsers did and so it can't be changed. But they're also synchronous if you use dispatchEvent:



    const e = new MouseEvent("click");
    btn.dispatchEvent(e);


    In that case, the handlers are still run synchronously, because the code using it might need to look at e to see if the default action was prevented or similar. (It could have been defined differently, providing a callback or some such for when the event was done being dispatched, but it wasn't. I'd guess that it wasn't for either simplicity, compatibility with click, or both.)






    const btn = document.querySelector('#btn');

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-1'); );
    console.log('click-1');
    );

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-2'); );
    console.log('click-2');
    );


    document.getElementById("btn-simulate").addEventListener("click", function()
    console.log("About to call click");
    btn.click();
    console.log("Done calling click");
    );

    <input type="button" id="btn" value="Direct Click">
    <input type="button" id="btn-simulate" value="Call click()">





    const btn = document.querySelector('#btn');

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-1'); );
    console.log('click-1');
    );

    btn.addEventListener("click", function()
    Promise.resolve().then(function() console.log('resolved-2'); );
    console.log('click-2');
    );


    document.getElementById("btn-simulate").addEventListener("click", function()
    console.log("About to call click");
    btn.click();
    console.log("Done calling click");
    );

    <input type="button" id="btn" value="Direct Click">
    <input type="button" id="btn-simulate" value="Call click()">






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 14 hours ago

























    answered 15 hours ago









    T.J. CrowderT.J. Crowder

    701k12412471341




    701k12412471341












    • To check my understanding. When I do .click(), it's as if I'm executing handler1(); handler2(); to completion, after which microtasks are executed ?

      – peonicles
      15 hours ago






    • 2





      Actually there are subtle differences between click and dispatchEvent (we run into those all the time when playing things at Testim and had to normalize). I'll see if I can dig up the chromium code later today to discuss. Also - note that .click is special and the answer to "why does it work this way" is "legacy, and because trusted events weren't always a thing" - .click is very special in the DOM (not to mention DOMActivate fun).

      – Benjamin Gruenbaum
      14 hours ago






    • 1





      I'll make a gist, but as a simple one every .click() reports (anonymously) to home base (Google) in Chrome (via RuntimeCallStatsCounter) in Chromium and dispatchEvent doesn't :D

      – Benjamin Gruenbaum
      14 hours ago






    • 1





      @BenjaminGruenbaum - Ugh, not a big fan of even anonymous phone-homes like that. Thanks! Wish I were going to FullStack London to see your talk, but I doubt I will be... :-| Maybe, though...

      – T.J. Crowder
      14 hours ago







    • 1





      Actually, not a lot of code, here: gist.github.com/benjamingr/915d0423f8bcf9db6d9fd852c28174ab

      – Benjamin Gruenbaum
      14 hours ago

















    • To check my understanding. When I do .click(), it's as if I'm executing handler1(); handler2(); to completion, after which microtasks are executed ?

      – peonicles
      15 hours ago






    • 2





      Actually there are subtle differences between click and dispatchEvent (we run into those all the time when playing things at Testim and had to normalize). I'll see if I can dig up the chromium code later today to discuss. Also - note that .click is special and the answer to "why does it work this way" is "legacy, and because trusted events weren't always a thing" - .click is very special in the DOM (not to mention DOMActivate fun).

      – Benjamin Gruenbaum
      14 hours ago






    • 1





      I'll make a gist, but as a simple one every .click() reports (anonymously) to home base (Google) in Chrome (via RuntimeCallStatsCounter) in Chromium and dispatchEvent doesn't :D

      – Benjamin Gruenbaum
      14 hours ago






    • 1





      @BenjaminGruenbaum - Ugh, not a big fan of even anonymous phone-homes like that. Thanks! Wish I were going to FullStack London to see your talk, but I doubt I will be... :-| Maybe, though...

      – T.J. Crowder
      14 hours ago







    • 1





      Actually, not a lot of code, here: gist.github.com/benjamingr/915d0423f8bcf9db6d9fd852c28174ab

      – Benjamin Gruenbaum
      14 hours ago
















    To check my understanding. When I do .click(), it's as if I'm executing handler1(); handler2(); to completion, after which microtasks are executed ?

    – peonicles
    15 hours ago





    To check my understanding. When I do .click(), it's as if I'm executing handler1(); handler2(); to completion, after which microtasks are executed ?

    – peonicles
    15 hours ago




    2




    2





    Actually there are subtle differences between click and dispatchEvent (we run into those all the time when playing things at Testim and had to normalize). I'll see if I can dig up the chromium code later today to discuss. Also - note that .click is special and the answer to "why does it work this way" is "legacy, and because trusted events weren't always a thing" - .click is very special in the DOM (not to mention DOMActivate fun).

    – Benjamin Gruenbaum
    14 hours ago





    Actually there are subtle differences between click and dispatchEvent (we run into those all the time when playing things at Testim and had to normalize). I'll see if I can dig up the chromium code later today to discuss. Also - note that .click is special and the answer to "why does it work this way" is "legacy, and because trusted events weren't always a thing" - .click is very special in the DOM (not to mention DOMActivate fun).

    – Benjamin Gruenbaum
    14 hours ago




    1




    1





    I'll make a gist, but as a simple one every .click() reports (anonymously) to home base (Google) in Chrome (via RuntimeCallStatsCounter) in Chromium and dispatchEvent doesn't :D

    – Benjamin Gruenbaum
    14 hours ago





    I'll make a gist, but as a simple one every .click() reports (anonymously) to home base (Google) in Chrome (via RuntimeCallStatsCounter) in Chromium and dispatchEvent doesn't :D

    – Benjamin Gruenbaum
    14 hours ago




    1




    1





    @BenjaminGruenbaum - Ugh, not a big fan of even anonymous phone-homes like that. Thanks! Wish I were going to FullStack London to see your talk, but I doubt I will be... :-| Maybe, though...

    – T.J. Crowder
    14 hours ago






    @BenjaminGruenbaum - Ugh, not a big fan of even anonymous phone-homes like that. Thanks! Wish I were going to FullStack London to see your talk, but I doubt I will be... :-| Maybe, though...

    – T.J. Crowder
    14 hours ago





    1




    1





    Actually, not a lot of code, here: gist.github.com/benjamingr/915d0423f8bcf9db6d9fd852c28174ab

    – Benjamin Gruenbaum
    14 hours ago





    Actually, not a lot of code, here: gist.github.com/benjamingr/915d0423f8bcf9db6d9fd852c28174ab

    – Benjamin Gruenbaum
    14 hours ago













    3














    dispatchEvent




    Unlike "native" events, which are fired by the DOM and invoke event
    handlers asynchronously via the event loop, dispatchEvent invokes
    event handlers synchronously.
    All applicable event handlers will
    execute and return before the code continues on after the call to
    dispatchEvent.



    dispatchEvent is the last step of the create-init-dispatch process,
    which is used for dispatching events into the implementation's event
    model. The event can be created using Event constructor.







    share|improve this answer























    • That's half of it. :-)

      – T.J. Crowder
      15 hours ago






    • 1





      @T.J.Crowder I'm your fan :D I love your comprehensive answers

      – ponury-kostek
      15 hours ago
















    3














    dispatchEvent




    Unlike "native" events, which are fired by the DOM and invoke event
    handlers asynchronously via the event loop, dispatchEvent invokes
    event handlers synchronously.
    All applicable event handlers will
    execute and return before the code continues on after the call to
    dispatchEvent.



    dispatchEvent is the last step of the create-init-dispatch process,
    which is used for dispatching events into the implementation's event
    model. The event can be created using Event constructor.







    share|improve this answer























    • That's half of it. :-)

      – T.J. Crowder
      15 hours ago






    • 1





      @T.J.Crowder I'm your fan :D I love your comprehensive answers

      – ponury-kostek
      15 hours ago














    3












    3








    3







    dispatchEvent




    Unlike "native" events, which are fired by the DOM and invoke event
    handlers asynchronously via the event loop, dispatchEvent invokes
    event handlers synchronously.
    All applicable event handlers will
    execute and return before the code continues on after the call to
    dispatchEvent.



    dispatchEvent is the last step of the create-init-dispatch process,
    which is used for dispatching events into the implementation's event
    model. The event can be created using Event constructor.







    share|improve this answer













    dispatchEvent




    Unlike "native" events, which are fired by the DOM and invoke event
    handlers asynchronously via the event loop, dispatchEvent invokes
    event handlers synchronously.
    All applicable event handlers will
    execute and return before the code continues on after the call to
    dispatchEvent.



    dispatchEvent is the last step of the create-init-dispatch process,
    which is used for dispatching events into the implementation's event
    model. The event can be created using Event constructor.








    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered 15 hours ago









    ponury-kostekponury-kostek

    4,95941324




    4,95941324












    • That's half of it. :-)

      – T.J. Crowder
      15 hours ago






    • 1





      @T.J.Crowder I'm your fan :D I love your comprehensive answers

      – ponury-kostek
      15 hours ago


















    • That's half of it. :-)

      – T.J. Crowder
      15 hours ago






    • 1





      @T.J.Crowder I'm your fan :D I love your comprehensive answers

      – ponury-kostek
      15 hours ago

















    That's half of it. :-)

    – T.J. Crowder
    15 hours ago





    That's half of it. :-)

    – T.J. Crowder
    15 hours ago




    1




    1





    @T.J.Crowder I'm your fan :D I love your comprehensive answers

    – ponury-kostek
    15 hours ago






    @T.J.Crowder I'm your fan :D I love your comprehensive answers

    – ponury-kostek
    15 hours ago












    1














    So, Chrome answer just because it's interesting (see T.J Crowder's excellent answer for the general DOM answer).



    btn.click();


    Calls into HTMLElement::click() in C++ which is the counterpart of the DOMElement:



    void HTMLElement::click() 
    DispatchSimulatedClick(nullptr, kSendNoEvents,
    SimulatedClickCreationScope::kFromScript);



    Which basically does some work around dispatchMouseEvent and deals with edge cases:



    void EventDispatcher::DispatchSimulatedClick(
    Node& node,
    Event* underlying_event,
    SimulatedClickMouseEventOptions mouse_event_options,
    SimulatedClickCreationScope creation_scope)
    // This persistent vector doesn't cause leaks, because added Nodes are removed
    // before dispatchSimulatedClick() returns. This vector is here just to
    // prevent the code from running into an infinite recursion of
    // dispatchSimulatedClick().
    DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<Member<Node>>>,
    nodes_dispatching_simulated_clicks,
    (MakeGarbageCollected<HeapHashSet<Member<Node>>>()));

    if (IsDisabledFormControl(&node))
    return;

    if (nodes_dispatching_simulated_clicks->Contains(&node))
    return;

    nodes_dispatching_simulated_clicks->insert(&node);

    if (mouse_event_options == kSendMouseOverUpDownEvents)
    EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseover,
    node.GetDocument().domWindow(),
    underlying_event, creation_scope))
    .Dispatch();

    if (mouse_event_options != kSendNoEvents)
    EventDispatcher(node, *MouseEvent::Create(event_type_names::kMousedown,
    node.GetDocument().domWindow(),
    underlying_event, creation_scope))
    .Dispatch();
    node.SetActive(true);
    EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseup,
    node.GetDocument().domWindow(),
    underlying_event, creation_scope))
    .Dispatch();

    // Some elements (e.g. the color picker) may set active state to true before
    // calling this method and expect the state to be reset during the call.
    node.SetActive(false);

    // always send click
    EventDispatcher(node, *MouseEvent::Create(event_type_names::kClick,
    node.GetDocument().domWindow(),
    underlying_event, creation_scope))
    .Dispatch();

    nodes_dispatching_simulated_clicks->erase(&node);



    It is entirely synchronous by design to make testing simple as well as for legacy reasons (think DOMActivate weird things).



    This is just a direct call, there is no task scheduling involved. EventTarget in general is a synchronous interface that does not defer things and it predates microtick semantics and promises :]






    share|improve this answer



























      1














      So, Chrome answer just because it's interesting (see T.J Crowder's excellent answer for the general DOM answer).



      btn.click();


      Calls into HTMLElement::click() in C++ which is the counterpart of the DOMElement:



      void HTMLElement::click() 
      DispatchSimulatedClick(nullptr, kSendNoEvents,
      SimulatedClickCreationScope::kFromScript);



      Which basically does some work around dispatchMouseEvent and deals with edge cases:



      void EventDispatcher::DispatchSimulatedClick(
      Node& node,
      Event* underlying_event,
      SimulatedClickMouseEventOptions mouse_event_options,
      SimulatedClickCreationScope creation_scope)
      // This persistent vector doesn't cause leaks, because added Nodes are removed
      // before dispatchSimulatedClick() returns. This vector is here just to
      // prevent the code from running into an infinite recursion of
      // dispatchSimulatedClick().
      DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<Member<Node>>>,
      nodes_dispatching_simulated_clicks,
      (MakeGarbageCollected<HeapHashSet<Member<Node>>>()));

      if (IsDisabledFormControl(&node))
      return;

      if (nodes_dispatching_simulated_clicks->Contains(&node))
      return;

      nodes_dispatching_simulated_clicks->insert(&node);

      if (mouse_event_options == kSendMouseOverUpDownEvents)
      EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseover,
      node.GetDocument().domWindow(),
      underlying_event, creation_scope))
      .Dispatch();

      if (mouse_event_options != kSendNoEvents)
      EventDispatcher(node, *MouseEvent::Create(event_type_names::kMousedown,
      node.GetDocument().domWindow(),
      underlying_event, creation_scope))
      .Dispatch();
      node.SetActive(true);
      EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseup,
      node.GetDocument().domWindow(),
      underlying_event, creation_scope))
      .Dispatch();

      // Some elements (e.g. the color picker) may set active state to true before
      // calling this method and expect the state to be reset during the call.
      node.SetActive(false);

      // always send click
      EventDispatcher(node, *MouseEvent::Create(event_type_names::kClick,
      node.GetDocument().domWindow(),
      underlying_event, creation_scope))
      .Dispatch();

      nodes_dispatching_simulated_clicks->erase(&node);



      It is entirely synchronous by design to make testing simple as well as for legacy reasons (think DOMActivate weird things).



      This is just a direct call, there is no task scheduling involved. EventTarget in general is a synchronous interface that does not defer things and it predates microtick semantics and promises :]






      share|improve this answer

























        1












        1








        1







        So, Chrome answer just because it's interesting (see T.J Crowder's excellent answer for the general DOM answer).



        btn.click();


        Calls into HTMLElement::click() in C++ which is the counterpart of the DOMElement:



        void HTMLElement::click() 
        DispatchSimulatedClick(nullptr, kSendNoEvents,
        SimulatedClickCreationScope::kFromScript);



        Which basically does some work around dispatchMouseEvent and deals with edge cases:



        void EventDispatcher::DispatchSimulatedClick(
        Node& node,
        Event* underlying_event,
        SimulatedClickMouseEventOptions mouse_event_options,
        SimulatedClickCreationScope creation_scope)
        // This persistent vector doesn't cause leaks, because added Nodes are removed
        // before dispatchSimulatedClick() returns. This vector is here just to
        // prevent the code from running into an infinite recursion of
        // dispatchSimulatedClick().
        DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<Member<Node>>>,
        nodes_dispatching_simulated_clicks,
        (MakeGarbageCollected<HeapHashSet<Member<Node>>>()));

        if (IsDisabledFormControl(&node))
        return;

        if (nodes_dispatching_simulated_clicks->Contains(&node))
        return;

        nodes_dispatching_simulated_clicks->insert(&node);

        if (mouse_event_options == kSendMouseOverUpDownEvents)
        EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseover,
        node.GetDocument().domWindow(),
        underlying_event, creation_scope))
        .Dispatch();

        if (mouse_event_options != kSendNoEvents)
        EventDispatcher(node, *MouseEvent::Create(event_type_names::kMousedown,
        node.GetDocument().domWindow(),
        underlying_event, creation_scope))
        .Dispatch();
        node.SetActive(true);
        EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseup,
        node.GetDocument().domWindow(),
        underlying_event, creation_scope))
        .Dispatch();

        // Some elements (e.g. the color picker) may set active state to true before
        // calling this method and expect the state to be reset during the call.
        node.SetActive(false);

        // always send click
        EventDispatcher(node, *MouseEvent::Create(event_type_names::kClick,
        node.GetDocument().domWindow(),
        underlying_event, creation_scope))
        .Dispatch();

        nodes_dispatching_simulated_clicks->erase(&node);



        It is entirely synchronous by design to make testing simple as well as for legacy reasons (think DOMActivate weird things).



        This is just a direct call, there is no task scheduling involved. EventTarget in general is a synchronous interface that does not defer things and it predates microtick semantics and promises :]






        share|improve this answer













        So, Chrome answer just because it's interesting (see T.J Crowder's excellent answer for the general DOM answer).



        btn.click();


        Calls into HTMLElement::click() in C++ which is the counterpart of the DOMElement:



        void HTMLElement::click() 
        DispatchSimulatedClick(nullptr, kSendNoEvents,
        SimulatedClickCreationScope::kFromScript);



        Which basically does some work around dispatchMouseEvent and deals with edge cases:



        void EventDispatcher::DispatchSimulatedClick(
        Node& node,
        Event* underlying_event,
        SimulatedClickMouseEventOptions mouse_event_options,
        SimulatedClickCreationScope creation_scope)
        // This persistent vector doesn't cause leaks, because added Nodes are removed
        // before dispatchSimulatedClick() returns. This vector is here just to
        // prevent the code from running into an infinite recursion of
        // dispatchSimulatedClick().
        DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<Member<Node>>>,
        nodes_dispatching_simulated_clicks,
        (MakeGarbageCollected<HeapHashSet<Member<Node>>>()));

        if (IsDisabledFormControl(&node))
        return;

        if (nodes_dispatching_simulated_clicks->Contains(&node))
        return;

        nodes_dispatching_simulated_clicks->insert(&node);

        if (mouse_event_options == kSendMouseOverUpDownEvents)
        EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseover,
        node.GetDocument().domWindow(),
        underlying_event, creation_scope))
        .Dispatch();

        if (mouse_event_options != kSendNoEvents)
        EventDispatcher(node, *MouseEvent::Create(event_type_names::kMousedown,
        node.GetDocument().domWindow(),
        underlying_event, creation_scope))
        .Dispatch();
        node.SetActive(true);
        EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseup,
        node.GetDocument().domWindow(),
        underlying_event, creation_scope))
        .Dispatch();

        // Some elements (e.g. the color picker) may set active state to true before
        // calling this method and expect the state to be reset during the call.
        node.SetActive(false);

        // always send click
        EventDispatcher(node, *MouseEvent::Create(event_type_names::kClick,
        node.GetDocument().domWindow(),
        underlying_event, creation_scope))
        .Dispatch();

        nodes_dispatching_simulated_clicks->erase(&node);



        It is entirely synchronous by design to make testing simple as well as for legacy reasons (think DOMActivate weird things).



        This is just a direct call, there is no task scheduling involved. EventTarget in general is a synchronous interface that does not defer things and it predates microtick semantics and promises :]







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 14 hours ago









        Benjamin GruenbaumBenjamin Gruenbaum

        193k65408442




        193k65408442



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55709512%2fwhy-is-there-a-difference-in-the-task-microtask-execution-order-when-a-button-is%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            -javascript

            Popular posts from this blog

            Mobil Contents History Mobil brands Former Mobil brands Lukoil transaction Mobil UK Mobil Australia Mobil New Zealand Mobil Greece Mobil in Japan Mobil in Canada Mobil Egypt See also References External links Navigation menuwww.mobil.com"Mobil Corporation"the original"Our Houston campus""Business & Finance: Socony-Vacuum Corp.""Popular Mechanics""Lubrite Technologies""Exxon Mobil campus 'clearly happening'""Toledo Blade - Google News Archive Search""The Lion and the Moose - How 2 Executives Pulled off the Biggest Merger Ever""ExxonMobil Press Release""Lubricants""Archived copy"the original"Mobil 1™ and Mobil Super™ motor oil and synthetic motor oil - Mobil™ Motor Oils""Mobil Delvac""Mobil Industrial website""The State of Competition in Gasoline Marketing: The Effects of Refiner Operations at Retail""Mobil Travel Guide to become Forbes Travel Guide""Hotel Rankings: Forbes Merges with Mobil"the original"Jamieson oil industry history""Mobil news""Caltex pumps for control""Watchdog blocks Caltex bid""Exxon Mobil sells service station network""Mobil Oil New Zealand Limited is New Zealand's oldest oil company, with predecessor companies having first established a presence in the country in 1896""ExxonMobil subsidiaries have a business history in New Zealand stretching back more than 120 years. We are involved in petroleum refining and distribution and the marketing of fuels, lubricants and chemical products""Archived copy"the original"Exxon Mobil to Sell Its Japanese Arm for $3.9 Billion""Gas station merger will end Esso and Mobil's long run in Japan""Esso moves to affiliate itself with PC Optimum, no longer Aeroplan, in loyalty point switch""Mobil brand of gas stations to launch in Canada after deal for 213 Loblaws-owned locations""Mobil Nears Completion of Rebranding 200 Loblaw Gas Stations""Learn about ExxonMobil's operations in Egypt""Petrol and Diesel Service Stations in Egypt - Mobil"Official websiteExxon Mobil corporate websiteMobil Industrial official websiteeeeeeeeDA04275022275790-40000 0001 0860 5061n82045453134887257134887257

            Frič See also Navigation menuinternal link

            Identify plant with long narrow paired leaves and reddish stems Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) Announcing the arrival of Valued Associate #679: Cesar Manara Unicorn Meta Zoo #1: Why another podcast?What is this plant with long sharp leaves? Is it a weed?What is this 3ft high, stalky plant, with mid sized narrow leaves?What is this young shrub with opposite ovate, crenate leaves and reddish stems?What is this plant with large broad serrated leaves?Identify this upright branching weed with long leaves and reddish stemsPlease help me identify this bulbous plant with long, broad leaves and white flowersWhat is this small annual with narrow gray/green leaves and rust colored daisy-type flowers?What is this chilli plant?Does anyone know what type of chilli plant this is?Help identify this plant