<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:admin="http://webns.net/mvcb/"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
	<channel> 

	<title>Comments on: WebKit Javascript Woes</title>
	<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes/</link>
	<description>Comments on Ask MetaFilter post WebKit Javascript Woes</description>
	<pubDate>Sat, 23 Sep 2006 13:46:13 -0800</pubDate>
	<lastBuildDate>Sat, 23 Sep 2006 13:46:13 -0800</lastBuildDate>
	<language>en-us</language>
	<docs>http://blogs.law.harvard.edu/tech/rss</docs>
	<ttl>60</ttl>

	<item>
		<title>Question: WebKit Javascript Woes</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes</link>	
		<description>I&apos;m having a strange problem with WebKit&apos;s Javascript engine. Please help. Copious explanation inside. &lt;br /&gt;&lt;br /&gt; I have a live inline comment preview feature, much like MetaFilter&apos;s, on my blog. It works great in Opera and Firefox (and MSIE). However, it doesn&apos;t seem to work in Safari, OmniWeb, or even the WebKit nightly build-I downloaded it in the hope that this was a WebKit bug that&apos;s fixed upstream in the nightlies, but if it &lt;i&gt;is&lt;/i&gt; their bug, it doesn&apos;t look like it&apos;s been fixed. I&apos;m asking this question in the hope that it&apos;s something &lt;i&gt;I&lt;/i&gt; can fix.&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
Here&apos;s how my comment preview code works:&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
1. There&apos;s a textarea with the id &quot;comment-text&quot; which you type your comment into. It has an onKeyUp event handler that calls doCommentPreview() in my javascript file. There&apos;s a preview field underneath the textarea with the id &quot;comment-preview&quot;, which doCommentPreview() fills with the preview HTML.&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
2. I have a blacklist of disallowed words, as a spam prevention measure. The comment engine will refuse any comment that contains any of these words or phrases.&lt;br&gt;
&lt;br&gt;
3. At the top of the document (not in the javascript file), I fill a javascript array called spams[] with the contents of the blacklist, using php, on the server side.&lt;br&gt;
&lt;br&gt;
4. I have two String prototype functions: showSpams() and regExEscape(). I use showSpams() to highlight items in the blacklist that a commenter might have typed in, to alert them right in the inline previewer that their comment is likely to be rejected before they hit post. It just tests the comment against each element of the spam[]array, and if the comments contains that particular word, it turns red and is surrounded by a border. &lt;br&gt;
&lt;br&gt;
5. I&apos;ve enabled the Debug menu using &lt;pre&gt;defaults write com.apple.Safari EnableDebugMenu 1&lt;/pre&gt; Safari&apos;s Javascript console, in the debug menu, shows the following error: &lt;pre&gt;Value undefined (result of expression re.compile) is not object. bloggie_05.js&lt;/pre&gt; on line 16.&lt;br&gt;
&lt;br&gt;
The line that WebKit complains about is the first line inside the for-loop in String.prototype.showSpams(): &lt;pre&gt;re.compile(spams[i].regExEscape(),&apos;gim&apos;);&lt;/pre&gt; 6. Here&apos;s all the code, in context:&lt;br&gt;
&lt;br&gt;
6-a. At the top of the document, in the &amp;lt;head&amp;gt; section: &lt;pre&gt;&amp;lt;script language=&quot;javascript&quot;&amp;gt;var spams = new Array();spams[0] = &apos;casino&apos;;spams[1] = &apos;craps&apos;;spams[2] = &apos;backgammon&apos;;spams[3] = &apos;cash advance&apos;;&amp;lt;/script&amp;gt;&lt;br&gt;
&amp;lt;script src=&quot;bloggie_05.js&quot;  language=&quot;javascript&quot; type=&quot;text/javascript&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt; [I abbreviated the blacklist (the spams[] array) because this question is already way too long.]&lt;br&gt;
&lt;br&gt;
In the textarea used for writing comments, I have this: &lt;pre&gt;&amp;lt;textarea tabindex=&quot;1&quot;  id=&quot;comment-text&quot; name=&quot;comment_text_body&quot; style=&apos;width:95%;height:300px;&apos; onKeyUp=&quot;javascript:doCommentPreview();&quot;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/pre&gt; And here&apos;s the empty div underneath it, which is filled by the doCommentPreview() function above: &lt;pre&gt;&amp;lt;div class=&quot;ientrycomment_body&quot; id=&quot;comment-preview&quot; name=&quot;prevu&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/pre&gt; Finally, here&apos;s the code in the external (bloggie_05.js) javascript file: &lt;pre&gt;function doCommentPreview(doc){&lt;br&gt;
	doc=(typeof(doc)==&quot;undefined&quot;?document:doc);&lt;br&gt;
	field=doc.getElementById(&quot;comment-text&quot;);&lt;br&gt;
	preview_field=doc.getElementById(&quot;comment-preview&quot;);&lt;br&gt;
	preview_field.innerHTML = &quot;&amp;lt;p&amp;gt;&quot; + field.value.split(/\n\n/).join(&quot;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&quot;).split(/\n/).join(&quot;&amp;lt;br /&amp;gt;&quot;).showSpams() + &quot;&amp;lt;/p&amp;gt;&quot;;&lt;br&gt;
}&lt;br&gt;
String.prototype.showSpams = function(){&lt;br&gt;
    despammed=this;&lt;br&gt;
    re = new RegExp();&lt;br&gt;
    for (var i=0; i &amp;lt; spams.length; i++) {&lt;br&gt;
        &lt;b&gt;re.compile(spams[i].regExEscape(),&apos;gim&apos;);&lt;/b&gt;&lt;br&gt;
        despammed=despammed.replace(re,&quot;&amp;lt;span style=\&quot;color:red;border:1px dotted;\&quot; title=\&quot;you can&apos;t say that here!\&quot;&amp;gt;&quot; + spams[i] + &quot;&amp;lt;/span&amp;gt;&quot;);&lt;br&gt;
    }&lt;br&gt;
    return despammed;&lt;br&gt;
}&lt;br&gt;
String.prototype.regExEscape = function() {&lt;br&gt;
  text=this;&lt;br&gt;
  if (!arguments.callee.sRE) {&lt;br&gt;
    var specials = [  &apos;/&apos;, &apos;.&apos;, &apos;*&apos;, &apos;+&apos;, &apos;?&apos;, &apos;|&apos;, &apos;(&apos;, &apos;)&apos;, &apos;[&apos;, &apos;]&apos;, &apos;{&apos;, &apos;}&apos;, &apos;\\&apos; ];&lt;br&gt;
    arguments.callee.sRE = new RegExp(&lt;br&gt;
      &apos;(\\&apos; + specials.join(&apos;|\\&apos;) + &apos;)&apos;, &apos;g&apos;&lt;br&gt;
    );&lt;br&gt;
  }&lt;br&gt;
  return text.replace(arguments.callee.sRE, &apos;\\$1&apos;);&lt;br&gt;
}&lt;/pre&gt;The line that WebKit has a problem with is in bold, in the String.prototype.showSpams() above.&lt;br&gt;
&lt;br&gt;
What&apos;s going on here?</description>
		<guid isPermaLink="false">post:ask.metafilter.com,2006:site.47114</guid>
		<pubDate>Sat, 23 Sep 2006 13:26:46 -0800</pubDate>
		<dc:creator>evariste</dc:creator>
		
			<category>safari</category>
		
			<category>webkit</category>
		
			<category>mac</category>
		
			<category>osx</category>
		
			<category>apple</category>
		
			<category>javascript</category>
		
	</item> <item>
		<title>By: MonkeySaltedNuts</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717802</link>	
		<description>re.compile is not a standard Javascript method.&lt;br&gt;
&lt;br&gt;
Why don&apos;t you just pass the pattern to &apos;new RegExp(pat)&apos;?</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717802</guid>
		<pubDate>Sat, 23 Sep 2006 13:46:13 -0800</pubDate>
		<dc:creator>MonkeySaltedNuts</dc:creator>
	</item><item>
		<title>By: evariste</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717809</link>	
		<description>MonkeySaltedNuts-For performance reasons. I don&apos;t want to create a new RexExp object for each of the some-80ish blacklisted terms in a loop. Reusing the same RegExp instance seemed wiser. OTOH, maybe that was a premature optimization, since I didn&apos;t actually check to see if it was causing performance problems, I just assumed it would and factored it out of the loop.&lt;br&gt;
&lt;br&gt;
compile isn&apos;t a standard method of RegExp objects? Damn...I guess that&apos;s my problem then. Too bad, it worked in every browser but WebKit ones.&lt;br&gt;
&lt;br&gt;
I&apos;ll try it without re.compile.</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717809</guid>
		<pubDate>Sat, 23 Sep 2006 14:25:49 -0800</pubDate>
		<dc:creator>evariste</dc:creator>
	</item><item>
		<title>By: evariste</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717812</link>	
		<description>Is there anywhere out there that has a Javascript compatibility chart, like the CSS browser compatibility charts that show which browsers can do what?</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717812</guid>
		<pubDate>Sat, 23 Sep 2006 14:29:30 -0800</pubDate>
		<dc:creator>evariste</dc:creator>
	</item><item>
		<title>By: Se&#xf1;or Pantalones</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717814</link>	
		<description>check to see if safari supports the compile method with a try/catch, and if not&lt;br&gt;
&lt;pre&gt;&lt;br&gt;
try {&lt;br&gt;
re.compile(spams[i].regExEscape(),&apos;gim&apos;);&lt;br&gt;
}&lt;br&gt;
catch {&lt;br&gt;
alert(&apos;guess we found the problem&apos;);&lt;br&gt;
// write a longer method of doing the same thing without use of the compile method&lt;br&gt;
}&lt;br&gt;
&lt;/pre&gt;&lt;br&gt;
or just detect &lt;br&gt;
&lt;pre&gt;if (!re.compile) alert(&apos;this browser doesn&apos;t support compile&apos;);&lt;/pre&gt;</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717814</guid>
		<pubDate>Sat, 23 Sep 2006 14:32:01 -0800</pubDate>
		<dc:creator>Se&#xf1;or Pantalones</dc:creator>
	</item><item>
		<title>By: evariste</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717817</link>	
		<description>That was it, Safari doesn&apos;t support the compile method. Thanks, Monkey and Se&#241;or!</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717817</guid>
		<pubDate>Sat, 23 Sep 2006 14:38:05 -0800</pubDate>
		<dc:creator>evariste</dc:creator>
	</item><item>
		<title>By: MonkeySaltedNuts</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717821</link>	
		<description>Javascript code (for pages) rarely needs to be optimized.&lt;br&gt;
&lt;br&gt;
If you really need to optimize I would pre-compute the REs for &apos;spams&apos; into &apos;spamREs&apos; rather than re-compute them everytime you invoke .showSpams on a string.</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717821</guid>
		<pubDate>Sat, 23 Sep 2006 14:56:31 -0800</pubDate>
		<dc:creator>MonkeySaltedNuts</dc:creator>
	</item><item>
		<title>By: evariste</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717824</link>	
		<description>&lt;i&gt;If you really need to optimize I would pre-compute the REs for &apos;spams&apos; into &apos;spamREs&apos; rather than re-compute them everytime you invoke .showSpams on a string.&lt;/i&gt;&lt;br&gt;
&lt;br&gt;
Duh.&lt;br&gt;
&lt;br&gt;
*smacks forehead*&lt;br&gt;
&lt;br&gt;
As it turns out, there&apos;s no need to optimize, so I&apos;m not going to worry about it for now. Thanks again.</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717824</guid>
		<pubDate>Sat, 23 Sep 2006 15:04:09 -0800</pubDate>
		<dc:creator>evariste</dc:creator>
	</item><item>
		<title>By: maciej</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717833</link>	
		<description>Hi, I&apos;m a Safari developer and I&apos;d love it if you could file this bug at http://bugzilla.opendarwin.org/ in product WebKit. Even if &quot;compile&quot; is not a standard RegExp method, we prefer to support common extensions of other browsers.</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717833</guid>
		<pubDate>Sat, 23 Sep 2006 16:04:58 -0800</pubDate>
		<dc:creator>maciej</dc:creator>
	</item><item>
		<title>By: Civil_Disobedient</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717836</link>	
		<description>&lt;i&gt;Javascript code (for pages) rarely needs to be optimized.&lt;/i&gt;&lt;br&gt;
&lt;br&gt;
This is absolutely not true.  Since JavaScript is not compiled, there are dozens and dozens of optimization routines that can speed up script execution.  Just for example, take this loop in the code you quote:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
for (var i=0; i &lt; spams.length; i++) {br&gt;
...&lt;br&gt;
&lt;/&gt;&lt;/code&gt;&lt;br&gt;
You&apos;re calculating the length of the &lt;code&gt;spams&lt;/code&gt; array every time you iterate through the loop.  You could optimize it by declaring a variable in the for...loop that holds the value of the length as such:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
for (i=0, j=spams.length; i &amp;lt; j; i++) {&lt;br&gt;
...&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
When you have large datasets that you need to perform operations on, like looping through a allowed-words filter, for instance, there are a number of real-world performance benefits to these relatively simple optimizations.&lt;br&gt;
&lt;br&gt;
That&apos;s just a simple, small example.  There are much larger issues looming in your routine.  For example, this is abhorrant:&lt;br&gt;
&lt;code&gt;&lt;small&gt;&lt;br&gt;
preview_field.innerHTML = &quot;&amp;lt;p&amp;gt;&quot; + field.value.split(/\n\n/).join(&quot;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&quot;).split(/\n/).join(&quot;&amp;lt;br /&amp;gt;&quot;).showSpams() + &quot;&amp;lt;/p&amp;gt;&quot;;&lt;br&gt;
&lt;/small&gt;&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
Why are you calculating the entire field value for &lt;b&gt;every single keystroke&lt;/b&gt;?  You could have a function in between your expression tester that checks whether a space or enter has been hit, and only then run the expression tester.</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717836</guid>
		<pubDate>Sat, 23 Sep 2006 16:24:36 -0800</pubDate>
		<dc:creator>Civil_Disobedient</dc:creator>
	</item><item>
		<title>By: Se&#xf1;or Pantalones</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717849</link>	
		<description>oh awesome, maciej is part of the hive mind!  now fix my filed bugs! ;)  (j/k).  &lt;br&gt;
&lt;br&gt;
civil_disobedient: crapping in the ice cream machine at a Dairy Queen is &quot;abhorrent.&quot; poorly optimized javascript is &quot;poorly optimized&quot; :)</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717849</guid>
		<pubDate>Sat, 23 Sep 2006 16:40:56 -0800</pubDate>
		<dc:creator>Se&#xf1;or Pantalones</dc:creator>
	</item><item>
		<title>By: evariste</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717856</link>	
		<description>maciej-great, I&apos;ll do that!&lt;br&gt;
&lt;br&gt;
Civil_Disobedient: thanks, I&apos;ve actually thought about that (only checking for blacklisted expressions on word boundary keystrokes) and decided not to do it, for now. Since there isn&apos;t any perceptible lag between a keystroke in the comment field and its mirror image showing up in the preview field, I&apos;m not too concerned about it.</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717856</guid>
		<pubDate>Sat, 23 Sep 2006 16:46:31 -0800</pubDate>
		<dc:creator>evariste</dc:creator>
	</item><item>
		<title>By: evariste</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717861</link>	
		<description>Filed bug #11001 against WebKit, thanks again maciej.</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717861</guid>
		<pubDate>Sat, 23 Sep 2006 16:58:03 -0800</pubDate>
		<dc:creator>evariste</dc:creator>
	</item><item>
		<title>By: MonkeySaltedNuts</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717885</link>	
		<description>&lt;b&gt;#&lt;a href=&quot;/mefi/47114#717836&quot;&gt;Civil_Disobedient&lt;/a&gt;&lt;/b&gt;: &lt;blockquote&gt;&lt;i&gt;Javascript code (for pages) rarely needs to be optimized.&lt;/i&gt;&lt;br&gt;
&lt;br&gt;
This is absolutely not true.  Since JavaScript is not compiled, there are dozens and dozens of optimization routines that can speed up script execution.  Just for example, take this loop in the code you quote:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
for (var i=0; i &amp;lt; spams.length; i++) {br&amp;gt;&lt;br&gt;
...&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
You&apos;re calculating the length of the &lt;code&gt;spams&lt;/code&gt; array every time you iterate through the loop.  You could optimize it by declaring a variable in the for...loop that holds the value of the length as such:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
for (i=0, j=spams.length; i &amp;lt; j; i++) {&lt;br&gt;
...&lt;/code&gt;&lt;/blockquote&gt;Are you insane? If a page takes .1 seconds to load and render, only the peversely obsessive will optimize associated code to save .0001 seconds and make it more opaque.&lt;br&gt;
&lt;br&gt;
(ps spams.length  does not &apos;calculate&apos; the length, it accesses the pre-calculated length, and the issue of when optimization is &lt;b&gt;really&lt;/b&gt; needed has nothing to do with the interpreted/compiled distinctions)</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717885</guid>
		<pubDate>Sat, 23 Sep 2006 17:45:49 -0800</pubDate>
		<dc:creator>MonkeySaltedNuts</dc:creator>
	</item><item>
		<title>By: Civil_Disobedient</title>
		<link>http://ask.metafilter.com/47114/WebKit-Javascript-Woes#717969</link>	
		<description>&lt;i&gt;ps spams.length does not &apos;calculate&apos; the length, it accesses the pre-calculated length&lt;/i&gt;&lt;br&gt;
&lt;br&gt;
No, you&apos;re right, it doesn&apos;t &lt;i&gt;calculate&lt;/i&gt; the length, but it has to access an object property.  The less property accessing that is done off of objects (or objects of objects of objects), the better.  For example:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
for (x=0; x &amp;lt; 100; x++) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;yo = document.forms[0].elements[1].value * x;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Will benefit from declaring the nested object &lt;i&gt;outside&lt;/i&gt; the loop, like this:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
formValue = document.forms[0].elements[1].value;&lt;br&gt;
for (x=0; x &amp;lt; 100; x++) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;yo = formValue * x;&lt;br&gt;
&amp;nbsp;&amp;nbsp;...&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;i&gt;Are you insane? If a page takes .1 seconds to load and render, only the peversely obsessive will optimize associated code to save .0001 seconds and make it more opaque.&lt;/i&gt;&lt;br&gt;
&lt;br&gt;
I was merely giving but one example to illustrate a point.  Iterating a nested object&apos;s value that never changes is a performance hit.  Not a big one, naturally. And actually, a better way to do it would be something like this:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
for (i=spams.length; i &amp;gt; 0; i--) {&lt;br&gt;
...&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
This will be roughly twice as fast as the original version.  If it&apos;s the &lt;i&gt;only&lt;/i&gt; optimization you&apos;re making, well sure, saving .001 second is pretty pointless.  But as your codebase gets bigger, these optimizations can make a palpable difference.&lt;br&gt;
&lt;br&gt;
As for keeping it &lt;i&gt;more opaque&lt;/i&gt;, you&apos;ll note that I made no mention of Duff Devices or the like.  I agree that there&apos;s a point when optimization negatively affects maintainability, but there are plenty of techniques that won&apos;t destroy code readability.</description>
		<guid isPermaLink="false">comment:ask.metafilter.com,2006:site.47114-717969</guid>
		<pubDate>Sat, 23 Sep 2006 20:40:16 -0800</pubDate>
		<dc:creator>Civil_Disobedient</dc:creator>
	</item>
	</channel>
</rss>
