6

Consider the following HTML:

<html>
    <head></head>
    <body>
        <input type="text" onblur="window.setTimeout('document.title += 2;', 0);" />
        <input type="button" onclick="document.title += 1" />
    </body>
</html>

[Demo with 0 delay, 100ms delay, 150ms delay]

And the following steps:

  • User enters the input (focus).
  • User clicks the button.

Now, the events would occur on the following order:

  • Input Text blur event.
  • Button click event.

Testing this on all reachable browsers I get:

document.title = '21' //Expected behavior

But! On production browser (Windows XP + IE 7), I get:

document.title = '12' //Unexpected behavior

I also tried simulating it in IE 7 mode on my local machine (IE 10), couldn't reproduce it tho.

This is obviously a simplified example of the problem I'm having. Otherwise I could simply get rid of the setTimeout.

In the real scenario, the setTimeout call is actually being made by a third party script library (ASP.NET Dev Express Components).

Apart from the actual solution to this problem (which I think I can handle), what explanation could be applied to this behavior?

Update:

Using the expression new Date().getTime() to get the time of each step executed by the browser. It happens as follows:

1387369361417 //document.title += 1
1387369361433 //document.title += 2
Mateus Schneiders
  • 4,853
  • 3
  • 20
  • 40
  • 1
    Maybe IE7 triggers the click event before the blur event? *"In that case, the button click event can't happen before the blur function."* How sure are you about this? – Felix Kling Dec 17 '13 at 16:35
  • 1
    @Felix Kling: Nope, without the setTimeout, it actually evaluates as `document.title ='21'` – Mateus Schneiders Dec 17 '13 at 16:38
  • If you don't use the window.setTimeOut function and you write `onblur="document.title += 2;"`, what is the output? – ProGM Dec 17 '13 at 16:38
  • I tested the exact HTML contained in the question with a dummy HTML file at production environment. 100% sure. – Mateus Schneiders Dec 17 '13 at 16:40
  • 1
    I bet this is because with setTimeout set to 0, the browser is returning idle at an unexpected time. – srquinn Dec 17 '13 at 16:40
  • @ProGM: Output is `document.title ='21'` – Mateus Schneiders Dec 17 '13 at 16:40
  • With a timeout of 10 instead of 0, the output is the same. – Mateus Schneiders Dec 17 '13 at 16:41
  • 1
    @jibsales: That was my theory. There's no guarantee when the function inside `setTimeout` will run. Even with `0` ms. `setTimeout('', 0)` actually puts the function at the bottom of the call stack, to be executed ASAP (ie whenever the browser feels like being idle). – gen_Eric Dec 17 '13 at 16:42
  • 3
    Every browser has a minimum default delay. Maybe it happens that in IE7 the default delay is too long. See https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout#Minimum.2F_maximum_delay_and_timeout_nesting – Felix Kling Dec 17 '13 at 16:42
  • @FelixKling: I think you're right! http://stackoverflow.com/a/9647221 – gen_Eric Dec 17 '13 at 16:43
  • But, actually, why you need to set a timeout of 0 millisecs to a code? What is the use case? – ProGM Dec 17 '13 at 16:46
  • 1
    @ProGM: This should explain it: http://stackoverflow.com/q/779379 – gen_Eric Dec 17 '13 at 16:48
  • @ProGM: As stated in the question, It's not my code, it's about third party components scripts (in this case, ASP.NET DevExpress Components). – Mateus Schneiders Dec 17 '13 at 16:48
  • @ProGM Its usually used when the time value is dynamic and you want immediate execution of the function. The confusion happens in that it doesn't actually immediately execute, rather, waits until the browser is idle from other tasks before execution. – srquinn Dec 17 '13 at 16:49
  • @ProGM In node.js parlance, this is functionally equivalent to `process.nextTick()` – srquinn Dec 17 '13 at 16:49
  • 4
    @Mt.Schneiders: Do you *really* need to support IE7? Our deepest condolences :( – gen_Eric Dec 17 '13 at 16:50
  • @Rocket Hazmat: Sadly, in this case, IE7 is the only browser that has to be supported. – Mateus Schneiders Dec 17 '13 at 16:53
  • As a workaround, why not try putting the `onclick` into a `setTimeout` with a timeout *longer* than that of the `onblur`? Would that work? – gen_Eric Dec 17 '13 at 16:57
  • That would cause a lot of rework, as this thing actually impacts a lot of pages. I'll probably have to hook several functions from the third party script and avoid using the `setTimeout` on a certain condition. – Mateus Schneiders Dec 17 '13 at 17:06

1 Answers1

1

Two possibilities:

  1. Your click (mousedown + mouseup) is finishing before IE7's minimum timeout period.
  2. The mousedown status is blocking scripts. Events must wait until other scripts and user-interactions are finished before they fire. And given the history of script-UI weirdness/terribleness in IE, I'd bet the mousedown "begins a user interaction" and the mouesup "ends user interaction". Load this up in IE7:

    <input type="text" onblur="window.setTimeout('output(2));', 0); output(3);" />
    <input type="button" onclick="output(1);" />
    

    http://jsfiddle.net/sMcE3/

    … and after you'd focus()'d on the text field, click that button real slow-like. I'm guessing you'll see 312. (As opposed to the 321 that any half-decent browser will show.)

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
svidgen
  • 13,744
  • 4
  • 33
  • 58