4

I've been trying to figure out how this is even possible. So I have an ASP.Net website. In the rendered HTML something like

<script type="text/javascript">
alert('should run once');
if(x === undefined){
  var x=true;
  alert('new x variable');
}else{
  alert('x exists');
}
</script>

However, for whatever reason what should run once, actually runs twice. When debugging under Firebug, I actually single step up to the alertnew x variable and at that point it will appear to display two alerts at once. Afterwards, it skips to x exists as if there are two separate threads running this same code. This does not occur in Internet Explorer 8, but does occur in Chrome and Firefox (latest versions as of this date)

So this what the alerts spit out as:

  1. should run once
  2. new x variable
  3. should run once
  4. x exists

I know I could workaround it by wrapping everything in a has_run variable, but I'd prefer to understand what is going on here.

The script block is not registered or anything, it is inserted plainly through a Literal control. Also, there is an UpdatePanel on the page, but this script block is not within the UpdatePanel, and I've confirmed that no UpdatePanel is doing a refresh. I've triple checked that this code is only in my HTML once. And no other HTTP requests(such as for an UpdatePanel) is being made when this loads. Just a few jQuery.ajax loads.

How is this even possible? How do I fix it?

Earlz
  • 62,085
  • 98
  • 303
  • 499
  • Do you have any iframes that are using the same script? – Chris Laplante Aug 03 '11 at 20:00
  • 1
    Using jsfiddle it works as intended (http://jsfiddle.net/4Zmuh/) but when used on a blank test page it returns the same results that you are getting. – ssell Aug 03 '11 at 20:02
  • @ssel what do you mean a blank test page? – Earlz Aug 03 '11 at 20:03
  • remove the 'var' on the line var x=true. – Aristos Aug 03 '11 at 20:03
  • @Earlz just an empty .html with NetBeans/Glassfish – ssell Aug 03 '11 at 20:04
  • @ssel I just tried that http://lastyearswishes.com/static/testjs.html didn't work. I can't reproduce this outside of our project – Earlz Aug 03 '11 at 20:07
  • 1
    I think you need to make the "divide to conquer" rule, by starting cleaning your page from code and from scripts till you get it working and at that stage you can know where is the root of the problem. – Samir Adel Aug 03 '11 at 20:09
  • @Samir I think the problem is the UpdatePanels on the page, but their not trivial to just remove – Earlz Aug 03 '11 at 20:10
  • I mean remove a part of the code that you doubt it might be the problem then if the problem still exist, remove another part and so on. – Samir Adel Aug 03 '11 at 20:10
  • Samir beat me to it. Your page doesn't work but the trivial test case does, so there's something funny going on in your code. – jdigital Aug 03 '11 at 20:10
  • @Earlz i think you will stay in a maze with this error if you didn't tried to isolate the problem. i tried this solution before for un reasonable errors and it helped me!! – Samir Adel Aug 03 '11 at 20:12
  • This is really a longshot, but figured I'd ask: are you doing any DOM-manipulation? Is it possible this code is getting fired once as the browser renders the page, then jquery relocates it to a different place in the DOM where it gets fired again when the browser renders that part of the DOM? – mikemanne Aug 03 '11 at 20:15
  • @Samir this is very difficult to do though. It's not trivial to just modify the HTML because of ASP.Net script references – Earlz Aug 03 '11 at 20:15
  • @mike that could be possible. I didn't think it'd get executed again upon moving it's DOM location – Earlz Aug 03 '11 at 20:16
  • BTW, upvote for this: "I know I could workaround it by wrapping everything in a has_run variable, but I'd prefer to understand what is going on here." I'm the same way! – mikemanne Aug 03 '11 at 20:17
  • If you can't divide and conquer, how about the opposite approach: take the trivial test case and build it up until it starts to exhibit the problem. – jdigital Aug 03 '11 at 20:18
  • Another longshot to try: get rid of the literal and just code the JS directly into the ASPX. I wonder if there's something to do with the viewstate and ASP.NET's handling of it that is causing some browser confusion. (that might also explain why IE doesn't exhibit the problem). – mikemanne Aug 03 '11 at 20:22
  • @mike nah, I'm inspecting the rendered HTML that is produced – Earlz Aug 03 '11 at 20:25
  • See my answer http://jsbin.com/akacah – Earlz Aug 03 '11 at 20:27

2 Answers2

2

I've figured this out with the help of @mikemanne

jQuery.dialog will move the dialog div in the DOM. So what this means is that it causes it to get executed twice, apparently possibly in a different thread causing erratic behavior.

An example: http://jsbin.com/akacah

Earlz
  • 62,085
  • 98
  • 303
  • 499
  • Interesting! Glad you got it figured out - thanks for sharing the result. A related issue I've encountered with jQueryUI components is: by default they are rendered outside the ASP.NET
    tag. Thus, any ASP.NET components in them are NOT included in the ViewState. This SO discussion addresses that problem: http://stackoverflow.com/questions/757232/jquery-ui-dialog-with-asp-net-button-postback. Cheers!
    – mikemanne Aug 03 '11 at 20:33
  • I've had this problem before. For some reason it didn't dawn on me that DOM manipulation could cause scripts to get executed twice though – Earlz Aug 03 '11 at 20:38
  • 1
    These quirks are why I try REALLY hard to keep all my JS in the HEAD, and out of the body. But sometimes it's unavoidable. – mikemanne Aug 03 '11 at 20:41
-1

var x = true; is hoisted above the if statement!

Nathan Romano
  • 7,016
  • 3
  • 19
  • 18
  • Not true. The `var x` part is hoisted, but the `= true` remains in the if statement. –  Aug 30 '11 at 09:58