Commonjs

每个模块都有 require exports module __filename __dirname变量

事实上,在编译的过程中,Node对获取的JavaScript文件内容进行头尾包装。 头部 (function (exports, require, module, __filename, __dirname) {, 尾部 });

(function (exports,require, module,__filename,__dirname){
var math = require('math');
exports.area =
function (radius) {return Math.PI * radius * radius;};
});

此外,许多初学者都曾经纠结过为何存在exports的情况下,还存在module.exports。理想情 况下,只要赋值给exports即可: 但是通常都会得到一个失败的结果。其原因在于,exports对象是通过形参的方式传入的, 直接赋值形参会改变形参的引用,但并不能改变作用域外的值。测试代码如下: 如果要达到require引入一个类的效果,请赋值给module.exports对象。这个迁回的方案不改 变形参的引用。

轮巡

  1. read
  2. select 1024 数组
  3. poll 链表
  4. epoll 事件和回调

事件循环

image-20240106192030989

image-20240106192101717

setTimeout()和setInterval()与浏览器中的API是一致的,分别用于单次和多次定时执行任务。它们的实现原理与异步1/0比较类似,只是不需要1/0线程池的参与。调用setTimeout()或者setInterval()创建的定时器会被插入到定时器观察者内部的一个红黑树中。每次Tick执行时,会从该红黑树中迭代取出定时器对象,检查是否超过定时时间,如果超过,就形成一个事件,它的回调函数将立即执行。 因此不能完全信任setTimeout()和setInterval()

nexttick(), setImmeidate()

Node在处理异常上形成了一种约定,将异常作为回调函数的第一个实参传回,如果为空值, 则表明异步调用没有异常抛出:

nodejs 事件, 订阅者发布者模式 Promise/Deferred模式? 中间件 next async parallel() waterfall() step 库 eval()

v8 垃圾回收

在V8中,所有的JavaScript对象都是通过堆来进行分配的。 主要将内存分新生代和老生代两代。

  1. 在分代的基础上,新生代中的对象主要通过Scavenge算法进行垃圾回收。在Scavenge的具体实现中,主要采用了Cheney算法, 先是在From空间中进行分配。当开始进行垃圾回收时,会检查From空间中的存活对象,这些存活对象将被复制到To空间中,而非存活对象占用的空间将会被释放。

  2. V8在老生代中主要采用了Mark-Sweep和Mark-Compact相结合的方式进行垃圾回收。 Mark-Sweep是标记清除的意思,它分标记和清除两个阶段。Mark-Sweep在标记阶段遍历堆中的所有对象,并标记活着的对象,在随后的清除阶段中,只清除没有被标记的对象。 没有被标记的对象。

  3. Mark-Compact是在Mark-Sweep的基础上演变而来的。它们的差别在于对象在标记死亡后,在整理的过程中,将活着的对象往一端移动,移动完成后,直接清理掉边界外的内存。

所以在取舍上,V8主要使用Mark-Sweep,在空间不足以对从新生代中晋升过来的对象进行分配时才使用Mark-Compact。