创造Node.js,并不是为了人们能在服务器上运行JavaScript,仅仅是因为Ryan Dahl想要一个建立在某高级语言之上的事件驱动型服务器框架。JavaScript碰巧就是适合干这个的语言。为什么?因为JavaScript语言可以完美地实现非阻塞式I/O。 在其他语言中,一不小心就会“阻塞”应用(通常是运行循环)直到完成I/O请求为止。而在JavaScript中,这种阻塞方式几乎沦为无稽之谈。类似如下的循环将永远运行下去,不可能停下来。 var ajaxRequest = new XMLHttpRequest; ajaxRequest.open('GET', url); ajaxRequest.send(null); while (ajaxRequest.readyState === XMLHttpRequest.UNSENT) { // readyState在循环返回之前不会有更改。 }; 相反,我们需要附加一个事件处理器,随即返回事件队列。 var ajaxRequest = new XMLHttpRequest; ajaxRequest.open('GET', url); ajaxRequest.send(null); ajaxRequest.onreadystatechange = function() { // ... }; 就是这么回事。不论是在等待用户的按键行为,还是在等待远程服务器的批量数据,所需要做的就是定义一个回调,除非JavaScript环境提供的某个同步I/O函数已经替我们完成了阻塞。 在浏览器端,Ajax方法有一个可设置为false的async选项(但永远、永远别这么做),这会挂起整个浏览器窗格直到收到应答为止。在Node.js中,同步的API方法在名称上会有明确的标示,譬如fs.readFileSync。编写短小的脚本时,这些同步方法会很方便。但是,如果所编写的应用需要处理并行的多个请求或多项操作,则应该避免使用它们。可在今天,还有哪个应用不是这样的呢? 有些I/O函数既有同步效应,也有异步效应。举例来说,在现代浏览器中操纵DOM对象时,从脚本角度看,更改是即时生效的,但从视效角度看,在返回事件队列之前不会渲染这些DOM对象更改。这可以防止DOM对象被渲染成不一致的状态。关于这点,可访问http://jsfiddle.net/ TrevorBurnham/SNBYV/,查看一个简单的演示。 console.log是异步的吗? WebKit的console.log由于表现出异步行为而让很多开发者惊诧不已。在Chrome或Safari中,以下这段代码会在控制台记录{foo:bar}。 EventModel/log.js var obj = {}; console.log(obj); obj.foo = 'bar'; 怎么会这样?WebKit的console.log并没有立即拍摄对象快照,相反,它只存储了一个指向对象的引用,然后在代码返回事件队列时才去拍摄快照。 Node的console.log是另一回事,它是严格同步的,因此同样的代码输出的却为{}。 JavaScript采用了非阻塞式I/O,这对新手来说是最大的一个障碍,但这同样也是该语言的核心优势之一。有了非阻塞式I/O,就能自然而然地写出高效的基于事件的代码。