深入浅出 nodejs

模块编译

Node 对获取的 JavaScript 文件内容进行了头尾包装:

(function (exports, require, module, __filename, __dirname)) {
    // 文件内容
    var math = require('math');
    exports.area = function(radius) {
        return Math.PI * radius * radius;
    }
    // 文件内容结束
})

有上述代码可以看出,使用 exports=function(){} 导出内容并不能生效,这是因为 exports 是形参。

JavaScript 层面上做位运算的效率不高,因为它现将 double 型数据转换成 int 型,再计算

异步 I/O 原理

让部分线程进行阻塞 I/O 或者非阻塞 I/O 加轮询技术来完成数据的获取,让一个线程进行计算处理,通过线程之间的通信将 I/O 得到的数据进行传递。

Node 异步 I/O

事件循环、观察者、请求对象、I/O线程池共同构成了 Node 异步 I/O 模型的基本要素。

事件循环

进程启动时,Node 便会创建一个类似于 while(true) 的循环,每执行一次循环体的过程我们称之为 Tick. 每个 Tick 的过程就是查看是否有事件待处理,如果有,就取出事件机器相关的回调函数。如果存在关联的回调函数,就执行它们。 然后就进入下个循环,如果不再有事件处理,就退出进程。

异步编程

Node 带来的最大特性是 基于事件驱动的非阻塞 I/O 模型 非阻塞 I/O 可以使 CPU 与 I/O 并不相互依赖等待,让资源得到更好的利用。Node 为了解决编程模型中阻塞 I/O 的性能问题,采用了单线程模型,这也导致了 Node 更像一个处理 I/O 密集型问题的能手,而 CPU 密集型问题却可能成了性能瓶颈(可以通过调用 C/C++ 扩展模块)。

难点1:处理异常

如下代码是使用 Java 代码处理异常时经常用到的:

try {
    JSON.parse(json);
} catch (e) {
    // handle exception
}

但是这对于异步编程来说并不适用。异步 I/O 主要包含两个阶段:提交请求和处理结果。这两个阶段中间有事件循环的调度,两者彼此并不关联。异步方法通常在第一个阶段提交请求后立即返回,但是异常并不一定在这个阶段发生。

var async = function(callback) {
    process.nextTick(callback);
}
try {
    async(callback)
} catch (e) {
}

调用 async() 方法后, callback 被存放起来,直到下一个事件循环才会取出来执行。尝试对异步方法进行 try/catch 操作只能捕获当次事件循环内的异常,对 callback 执行时抛出的异常无能为力。

异步方法一般遵循一些原则:

  • 必须执行调用者传入的回调函数
  • 正确传递回异常供调用者判断
navigate_before navigate_next