Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does setTimeout(.., 0) trigger before browser action in Firefox? Bug?

I have an input.onkeydown handler and I check input.value after setTimeout(..0).

I expect input.value to have the new value when the setTimeout callback runs.

In all browsers except Firefox it does. In Firefox it's not always the case.

The code to check is:

<input id="input">
<script>
  input.onkeydown = function() {
    setTimeout(() => this.value = this.value.toUpperCase());
  };
</script>

The demo: http://plnkr.co/edit/rZmiHdttSXNdpKkR8YbH?p=preview

As I uppercase the input value after setTimeout(..0), it should be uppercased always. But as said, in Firefox it's not.

Here's the demo video; the first few seconds demonstrate the problem: https://jmp.sh/9XSROQ2

The relevant spec part is https://dom.spec.whatwg.org/#concept-event-dispatch.

Am I not getting something, or is this a long-standing bug in Firefox?

P.S. If I add console.log in setTimeout, I sometimes see the old value.

P.P.S. The purpose of this question is to know if I understand setTimeout correctly or not. I'm familiar with a variety of ways to uppercase input; please do not suggest oninput, requestAnimationFrame, or such.

like image 925
Ilya Kantor Avatar asked Jun 25 '19 08:06

Ilya Kantor


People also ask

What is the use of setTimeout 0?

Invoking setTimeout with a callback, and zero as the second argument will schedule the callback to be run asynchronously, after the shortest possible delay - which will be around 10ms when the tab has focus and the JavaScript thread of execution is not busy.

How do I avoid setTimeout?

You can also prevent the setTimeout() method from executing the function by using the clearTimeout() method. If you have multiple setTimeout() methods, then you need to save the IDs returned by each method call and then call clearTimeout() method as many times as needed to clear them all.

What happens when if setTimeout () call with 0ms?

If you call setTimeout() with a time of 0 ms, the function you specify is not invoked right away. Instead, it is placed on a queue to be invoked “as soon as possible” after any currently pending event handlers finish running.

How do I Turn Off the timeout in Firefox?

Depending on the way you use firefox, either may be helpful. If you want to extend your timeout, type about:config in your search bar on the top. From there it will take you to a list of preferences. There is a search bar. Type "Timeout" into it. The top two are disable timeout and the "count timeout".

What is the difference between setInterval and setTimeout in Mozilla?

Mozilla's docs expand that to cover repeated, not just nested cases (so setInterval with interval of 0 will reschedule immediately a few times, then delay longer after that), but simple uses of setTimeout with minimal nesting are allowed to immediately queue.

What does setTimeout(fn/0) do in JavaScript?

Javascript is single threaded application so that don't allow to run function concurrently so to achieve this event loops are use. So exactly what setTimeout (fn, 0) do that its pussed into task quest which is executed when your call stack is empty.

How to implement 0 Ms timeout in a modern browser?

Historically browsers sets this minimum to 10 milliseconds, but the HTML5 specs and modern browsers have it set at 4 milliseconds. If nesting level is greater than 5, and timeout is less than 4, then increase timeout to 4. To implement a 0 ms timeout in a modern browser, you can use window.postMessage () as described here.


1 Answers

The actual specs are here and actually do not define the relation between the keydown and the change of the input's current value.

However they read, (emphasize mine)

For input elements without a defined input activation behavior, but to which these events apply, any time the user causes the element's value to change without an explicit commit action, the user agent must queue a task to fire an event named input at the input element, with the bubbles attribute initialized to true. The corresponding change event, if any, will be fired when the control loses focus.

So it is actually specced that the input event (that you should be listening to anyway) must fire asynchronously. Since this event is the one that testifies of a change in the current value, I don't think Firefox's behavior of applying the changes caused by the Key event in the next event loop is hardly a bug; remember that browsers have to make this change asynchronously after the event is dead (and can't be cancelled anymore by any handler).

Some additional notes (which may be related to a real cause btw), inputing a combined character (e.g ^ + a => â) I have a 100% repro in FF on macOs (because yes, I suspect it may also be related to the OS).

But of course, even if it doesn't go against any specs, and even if you have an easy fix (listen for input event) you may still want to file a bug-report at least for not behaving like other vendors.

like image 181
Kaiido Avatar answered Oct 19 '22 23:10

Kaiido