leechael.orgHome

在 Web-App 中侦测浏览器是否启用了 JavaScript

虽然 noscript 很好用,但这不再是标准中 recommended 的标签。PPK 在其的 《PPK on JavaScript》 中曾提及使用 location.replace() 取代 noscript 的方法:

window.onload = function(){
location.replace('http://path.to/target');
}

可这般为每一个 ajax 页面创建一个侦测页面似乎有点浪费,虽然可以机器生成,但也不是一个很好的办法。由于在 Web-App 中,绝大部分的包含 JavaScript 的页面都是动态页面,我们可以使用一个专有的脚本对浏览器进行判别是否启用了 JavaScript,然后使用 location.replace() 重定向。假设我们目标页面为 /foo.php, 而在运行这个脚本以前,用于进行是否启用的 JavaScript 的脚本是 /jsdetector.php。

在 jsdetector.php 输出的页面中,我们尽可发挥创造力,做一个很漂亮、state-of-the-art 的页面,而只需要在 head 中使用 PHP 输出一句:

echo '<script type="text/javascript">location.replace("/' . $_GET['target'] . '.php");</script>';

然后,我们把所有 /foo.php 的链接替换为 /jsdetector.php?target=foo。

为了避免用户直接访问 /foo.php 这个页面、绕开浏览器的检测,在 foo.php 输出任何内容之前,进行一个小小的检测:

$referer = strtolower( basename( $_SERVER['HTTP_REFERER'], '.php' ));
if ( $referer !== 'foo' ) {
header( 'Location: /foo' );
}

这般我们就能得到一个较为简便的方法,来进行浏览器是否启用了 JavaScript 的检测。当然,我们也可以使用 Apache 的 Rewrite 功能,让这一切看起来都更为语义化、隐藏 jsdetector.php 的存在:

RewriteRule ^/fetch/foo$ /jsdetector.php?target=foo [L]
RewriteRule ^/fetch/bar$ /jsdetector.php?target=bar [L]
RewriteRule ^/fetch/baz$ /jsdetector.php?target=baz [L]
RewriteRule ^/foo$ /foo.php [L]
RewriteRule ^/bar$ /bar.php [L]
RewriteRule ^/baz$ /baz.php [L]

两个 JavaScript 的测试

第一个是 JavaScript 在不同浏览器下的速度测试,原文对 Firefox 3.0.7a, Firefox 2.0.0.6, IE7, IE6, Safari 3.0.3, Opera 9.23, Opera 9.50a 分别进行了测试。原文中附带了测试,而我的测试结果是:

ArrayDateErrorMathRegExStringDOMAJAXTotal
Firefox 2.0.0.1129778941413287812510782219
Firefox 3.0b3pre
(Gecko/2007121405)
3115151652661871337731621
Internet Explorer 7.0
(With Add-ons)
633194125344931723751297
Safari 3.0.47816626320331203110766
Opera 9.241564763781561256393781

与原文的结果相比,Firefox 3 还在继续改进,但总体结果还是不及 IE7(这个结果让人惊讶)。而 Safari 和 Opera 在 JavaScript 运算上的优越简直让人惊讶,这让我觉得在接下来的时间里,单靠众多的 Add-ons 的来支撑的 Firefox 还会不会是众多用户除了 IE 以外的首个选择。要说 Firefox 存在的优势,就是 DOM 方面的运算极快,但还是不及 Opera。AJAX 方面更是让人失望,很明显地也不如 IE7,无论是现时主流的 Firefox2 还是处于 beta 状态的 Firefox3。若非开发,日常使用大可考虑使用 Opera 或者 Safari —— 这是我的结论。

原文叫做 Javascript Speed Test 2007,但貌似测试的时间距离现在也有一段日子了,有兴趣的同学也可以自己做一做测试。

而另一个是关于在 JavaScript 中,使用 Closure 及使用 Object Properties 间性能的比较。当然这个比较是有点无意义的感觉,原文 中也只对 Firefox2 及 IE7 做了比较。这里补充上我的一些测试结果:

ClosureWritingReadingExternal ReadingExternal Writting
Firefox 2.0.0.11Closures39216315161593
Properties48919312191250
Firefox 3.0b3pre
(Gecko/2007121405)
Closures37257217451761
Properties690812313551407
Internet Explorer 7.0Closures482810963593485
Properties584418820312015
Safari 3.0.4Closures953172797953
Properties1921172484531
Opera 9.24Closures120394766859
Properties1172109343516

这个测试除了再一次证明 Safari 和 Opera 在 JavaScript 运算速度上的优越,而在 Closure 和 Object Properties 使用上的选择,和原文一般的观点:如果有在外部读取和写入需要,使用 Object Properties,在仅是内部使用的情况下更多地考虑选择 Closure。

References

PS: 你认为你的 CSS 能力在哪个阶段呢?这里 有一个简单的评定条件,我给自己评的是 4.6 (虽然没有这个数字……),各位认为这个数字会不会偏高了呢?哪位同学有意打击我,现在机会来了……;P

JavaScript 的内存泄漏

今天在看到 IEBlog 的一篇关于检测 IE 内存泄漏工具的文章: Tools for Detecting Memory Leaks,说实话,我到此刻才知道 JavaScript 的不当会造成内存泄漏。文中有提到两个检测内存泄漏的工具,DripsIEve。由于这两个工具仅是针对 IE——而在这世界上,不仅是 IE,我们还有 Firefox, Safari, Opera, Konqueror, etc.内存泄漏的问题——不会仅是存在于 IE 之中,对于 Firefox,我们可以使用 Leak Monitor 来进行检测;Safari Blog 在很早以前也提及过 如何检测内存泄漏的问题;至于 Opera——貌似是一个很坚固的浏览器,如果解决掉中文字体设置困难这个问题,然后对 CSS3 有更多的支持,会是一个很强大的东西。

随着 Web-Application 的增多,以及各个网站开始使用 JavaScript 来增强效果,随之带来的问题,例如 XSS,Memory Leaks,都需要开发人员花费更多的时间来进行调试。

References

Unobtrusive JavaScript: To Be or Not To Be

印象中国内并没有多少人会提及 Unobtrusive JavaScript(低调的 JavaScript/不乱入的 JavaScript, 前者是在国内一 blog 看见的翻译,后者是对岸的一位设计师 Othree 的翻译)。本来这也不是很大的问题,倡导 CSS/JavaScript/HTML 代码分离是很多设计师们倡导的事情。有一篇 The seven rules of Unobtrusive JavaScript 说了七点 Unobtrusive JavaScript 要注意到的事情:

  • 不作任何假定。
  • 找到你的 JavaScript 在 HTML 代码中的接入点及与其的关系
  • 将遍历 (Traversing) 留给专家(利用 CSS 来找寻你需要的元素)
  • 了解浏览器和用户
  • 了解事件(Events)
  • 不与其他代码冲突
  • 为下一个开发者工作

在看到最后一点后,一些东西就不再奇怪了。Unobtrusive JavaScript 倡导了一种良好的编码习惯,而实际上,或者说一句不中听的,这是给代码工人的规则。

Plaxo 的 Joseph Smarr 有一个很棒的、关于提高 JavaScript 的 slides: High Performance JavaScript。其中说到: Directly attach onclick, etc. handlers instead using event listeners where appropriate(尽可能地直接使用 onclick 等控制事件而不是事件冒泡).原因很简单,因为 Finding by class/attaching event handlers is slow.例如我需要那些 class 为 pop 的链接在点击后自动打开新窗口,当然我们可以通过编写一个额外的脚本来监控这些链接的点击,但在这些链接中使用 onclick 会让脚本运行得更快,但维护起来也会很麻烦。

而事实上,我们是否需要这般完整的分离代码呢?很大的可能是看这个站点对 JavaScript 的依赖程度。如果是轻度使用 JavaScript 来增强用户体验,Unobtrusive JavaScript 是很好的习惯;如果是那些 Web Application,例如,由于需要更多地考虑 JavaScript 的执行效率,就不必碍于 Unobtrusive JavaScript 的规则,适当地在 HTML 代码中插入 JavaScript 代码也未尝不可。

深究起来,其实这和编程中常见的、关于程序的 scalability 和 performance 的衡量,没有什么区别。