Joho the Blog » beginner2beginner

August 1, 2010

Beginner to Beginner: When a Javascript program only works in a debugger

[LATER the same day:] Thanks to expert advice from some generous expert folks in the comments, I found the mistake I was making; I explain it in the comment #5. But, the mystery of why it worked only when run in debug mode remains. (Tom in comment #4 has a good hypothesis.) Nevertheless, I’m sticking with my overall point that for a home-made, one-user project like this, a brute-force, dumb-ass solution sometimes serves. I should maybe mention also that one reason I post about “programming” is precisely because I’m an idiot about it, and I think it’s good to be a beginner in public.

Aaarrrggghhh. I spent way too much time yesterday and today trying to fix a problem with a javascript program the right way. When I finally gave up and did it the wrong way, it worked fine…except for being embarrassingly inelegant.

It’s a mystery. The program doesn’t work ever except if you run it in a debugger and set a breakpoint anywhere in either of the two affected functions. It doesn’t even work if you put an “alert()” into it. It really really wants a breakpoint. This is consistent in both Firefox and Chrome, with Firebug and the integrated Chrome debugger. It only works if you set a breakpoint. It does not work if you do not set a breakpoint. Did I mention Aaaarrrrrrggggghhhhhh?

Some details: I added a function to my little all-crap blog editor. The function (call it FunctionA) gets called when the user (= me and only me) presses a button. FunctionA calls FunctionB to see if the selected text is listed in an array of terms. If so, then FunctionA inserts some text using associated text. (To be more concrete, although it doesn’t matter: If the selected text is the name of someone for whom I have a twitter name, FunctionA builds and inserts a link to the person’s Twitter address.) FunctionB calls one other function (that trims spaces and other cruft) and one method (to temporarily uppercase both the selected text and the name in the database, so that the search won’t be case sensitive, and yes, I’m sure there’s a better way to do that). Then it simply walks through the array, looking for a match.

I googled around and didn’t find much help with the mysterious fact that it only works if I set a breakpoint. People with similar problems can sometimes solve them by using the setTimeout() function, to let the script catch up with itself. But, that’s not really what setTimeout does, apparently. It doesn’t pause the script. Rather, it delays the execution of a particular function while the rest of the script continues merrily on. I also found that a common cause of a similar problem is that your script is trying to access a part of the document that hasn’t been loaded or created yet. But: (a) My script isn’t trying to do that, and (b) If that were the problem, then putting in an alert() would have worked for me, no? The cause might be some multithreaded mystery for which there is no known solution, but I really don’t know. (You might try this.)

So, after looking at some clever recursive setTimeout strategies that I couldn’t figure out how to adapt to my particular script, I had a stupid idea. I put the code from FunctionB — the one that looks the selected text up in an array — straight into FunctionA. So, FunctionA doesn’t call FunctionB. It has within it a copy of the code in FunctionB.

And it works.

It works even though it is just about the definition of “inelegant.” The whole point of every programming language since Turing first ran marked paper off a mental spool is to write functions for any process your script might use more than once. Not only does that save time writing, it makes debugging a billion times easier because you only have to fix it in one place. So my solution to my problem is like telling a chef to beat each egg separately or to suggest reloading a supersoaker after each and every squeeze.

But, dammit, it worked. I don’t know why, and I ‘d say that I don’t care, but, I do. Well, at least I can now get back to wasting my time in marginally less frustrating ways.

8 Comments »