setTimeout(..,0) triggers before default browser action
Categories
(Core :: DOM: Core & HTML, defect, P3)
Tracking
()
People
(Reporter: iliakan, Unassigned)
References
(Depends on 1 open bug)
Details
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
Steps to reproduce:
Here's the full example: http://plnkr.co/edit/rZmiHdttSXNdpKkR8YbH?p=preview
I uppercase input value after setTimeout(..0) in keydown event handler.
<input id="input">
<script>
input.onkeydown = function() {
setTimeout(() => this.value = this.value.toUpperCase());
};
</script>
Actual results:
The input value is sometimes uppercased, sometimes not.
Here's the demo video: https://jmp.sh/9XSROQ2
Expected results:
I expect setTimeout to run after the default browser action.
-I tested the behavior in Chrome, Safari, Edge => all of them have the new value after zero timeout. Only Firefox is different.
- According to the specification https://dom.spec.whatwg.org/#concept-event-dispatch, it looks that updating the input value should be finished by the moment when the next macrotask triggers.
Comment 1•5 years ago
|
||
Build ID 20190626215508
User Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:69.0) Gecko/20100101 Firefox/69.0
I've managed to reproduce this issue on the latest release version (v67.0.4) and also on the latest Nightly build (v69.0a1).
Updated•5 years ago
|
Comment 2•5 years ago
|
||
This depends on keypress/up timing. Nothing defines whether keypress or keyup should happen before or after setTimeout.
Comment 3•5 years ago
|
||
(In reply to Olli Pettay [:smaug] from comment #2)
This depends on keypress/up timing. Nothing defines whether keypress or keyup should happen before or after setTimeout.
Is it worth defining this?
Comment 4•5 years ago
|
||
UA is free to run setTimeout callback whenever. The question is how keydown and keypress relate to each others - whether they should be in the same task or so.
Masayuki, do you recall if this has been discussed @w3c in the context of key event handling?
The issue also randomly happens with keypress: http://next.plnkr.co/edit/HaNrKmAGiMqVEK3J (as well as with keydown)
Isn't defined that a browser action on <input type="text"> should trigger in the current event loop?
(At least all other browsers behave the same way here, different from Firefox)
Comment 7•5 years ago
|
||
(In reply to iliakan from comment #5)
Isn't defined that a browser action on <input type="text"> should trigger in
the current event loop?
Default action to what?
And Gecko does handle default action synchronously.
Browser default action (updating the input value) should happen in the same event loop with the event handler, not some time after it.
Or you suggest that the browser can update the input value any time, even after keypress/keydown
handlers triggered, and other events happened? That would be strange.
Also:
| And Gecko does handle default action synchronously.
That's contrary to the demo, if we're talking about the same thing of course.
Comment 10•5 years ago
|
||
The question is default action of which event? Gecko does do default action of key events synchronously, but it is possible that other browsers use fewer or more task for key events - like, are keydown and keypress in the same task or in separate tasks (that isn't defined in any specification). If they are in separate tasks, setTimeout may run between them.
Reporter | ||
Comment 11•5 years ago
|
||
Of keydown/keypress events, of course, please see the report.
Comment 12•5 years ago
|
||
(In reply to Olli Pettay [:smaug] from comment #4)
UA is free to run setTimeout callback whenever. The question is how keydown and keypress relate to each others - whether they should be in the same task or so.
Masayuki, do you recall if this has been discussed @w3c in the context of key event handling?
I don't understand the point... and I've never seen such discussion about race condition of DOM events.
But looks like that the cause is that the keydown
event listener does not call Event.preventDefault()
. Therefore, there is a race between the following keypress
event which will put a character into the <input>
and the function kicked by setTimeout()
.
Comment 13•5 years ago
|
||
A question is whether keydown and keypress happen in the same task, or different tasks. But ok, that hasn't been discussed at least in W3C/key event handling design.
Reporter | ||
Comment 14•5 years ago
|
||
Dear Sirs, could you please just tell me, is it ok that setTimeout(f)
initiated in keydown (or keypress) input handler, runs before its value is updated?
Comment 15•5 years ago
|
||
I haven't managed to reproduce the issue when setTimeout is used with keypress testcase. On which platform does it happen?
We do update the value on keypress, and setTimeout runs asynchronously, so it is hard to see how the issue could even happen there, unless some character value depends on multiple keypress events or something.
What do you type when you see the issue with http://next.plnkr.co/edit/HaNrKmAGiMqVEK3J ?
setTimeout used with keydown and running before keypress is ok per current specifications, since nothing says keydown and keypress happen within the same task, so user agent may schedule the timeout to run between keydown and keypress (and keypress updates <input>'s value.)
Reporter | ||
Comment 16•5 years ago
|
||
Here's a simplified test stand: http://next.plnkr.co/edit/7evX72VCmzesqeR8?preview
Just focus on input and type letters until you meet Whoops!
Reload the page and try again if doesn't reproduce.
Reproduced on MacOS 10.14 soon, on Windows 10 took a bit time (Firefox 68.0b12).
If I change keypress to keydown, it feels like it reproduces faster.
Comment 17•5 years ago
|
||
I don't understand what that test case tries to test. A new keypress event may have been handled already when the setTimeout runs, so of course 'this.value.slice(-1) != e.key' is possible.
Reporter | ||
Comment 18•5 years ago
|
||
Olli: you're right, the previous test example with uppercasing was more obvious.
Here's the 4-second video from the previous test case, where the issue got reproduced immediately: http://ilyakantor.ru/olli.mp4
Reporter | ||
Comment 19•5 years ago
|
||
P.S. I'm typing all lowercase letters, but on the first letter setTimeout triggers before the input value is updated (that's the issue) (only happens in Firefox).
Reporter | ||
Comment 20•5 years ago
|
||
P.P.S. If I replace keydown with keypress, then setTimeout always has the right value. At least I couldn't reproduce the issue.
Maybe that's related with the discussion of keydown/keypress above? :)
Comment 21•5 years ago
|
||
Yeah, so the question is that should keydown and press happen in the same task.
Masayuki, can you think of from top of your head issues if we send them as a one IPC message to the child processes?
Comment 22•5 years ago
|
||
Ideally, we should stop dispatching eKeyPress
event from widget and put all information into eKeyDown
event. Then, we can reduce the IPC cost for every key press to half. I filed bug 1181501, but I don't have much time to do that. It might be worthwhile me to work on it after shipping beforeinput
event, though.
Updated•2 years ago
|
Description
•