GoMind Hub

Nodejs

计算机知识思维导图:Nodejs。网页展示前三层结构,可在线查看完整脑图并下载 GoMind 文件。

2026-08-25

计算机知识学习资料思维导图
## Nodejs
### Nodejs
#### 异步流程控制
##### Promise
##### co模块
##### async模块
##### async/await
#### apply/call
##### apply
##### call
##### bind
##### 绑定后立即执行
##### 绑定后非立即执行
#### 非IO异步Api
##### settimeout
##### setInterval
##### setImmediate
##### process.nextTick
##### 内部由红黑树实现,时间复杂度为O(lg(n))
##### 优先级对比: process.nextTick > setImmediate > setTimeout = setInterval , idle观察者优于IO观察者,IO观察者优于check观察者, process.nextTick 属于idle观察者,setImmediate属于check观察者
#### 闭包
##### 用处
##### 注意
#### 常用框架
##### express
##### koa
#### 优先级对比
##### 同步代码(包括promise的构造函数) -> promise.then -> setTimeout , 实际上promise.then内部会根据系统来判断,若系统支持setImmediate则直接执行该函数,否则执行process.nextTick

> 仅展示前三层结构;请在线查看完整脑图或下载 GoMind 文件。

Nodejs

Nodejs
对象的状态不受外界影响
一旦状态改变就不会再变
两大特点
pending
fullfilled
rejected
三种状态
一旦建立就会立即执行,无法中途取消
内部抛出的错误无法反应到外部,同时异常堆栈没有记录出错的具体位置
当处于pending状态时,无法得知目前进展到哪个阶段
若业务逻辑过多会导致有过多的then及嵌套,导致代码可读性变差
调试不方便
缺点
Promise
promise
thunks
array
objects
generators
generator functions
yield后面的数据类型
并发异步
// 数组的写法

co(function* () {

  var res = yield [

    Promise.resolve(1),

    Promise.resolve(2)

  ];

  console.log(res); 

}).catch(onerror);



// 对象的写法

co(function* () {

  var res = yield {

    1: Promise.resolve(1),

    2: Promise.resolve(2),

  };

  console.log(res); 

}).catch(onerror);
co模块
基于 ES6 的 generator 和 iterator实现



将生成器放到co方法参数中执行。

即 generator自动执行函数库。
模块导出分析
由于现在js使用的范围非常广,又有后端nodejs,又有前端js,需要适应不同的导入操作。这段代码就可以非常完美地做到对于不同导入方式的支持,包括:



nodejs中的require语法



RequireJs的导入方式



html中script标签的导入方式





// Node.js

if (typeof module === 'object' && module.exports) {

   module.exports = async;

}

// AMD / RequireJS

else if (typeof define === 'function' && define.amd) {

   define([], function () {

       return async;

   });

}

// included directly via <script> tag

else {

   root.async = async;

}
async模块
会返回Promise.resolve(undefined)
无返回值
返回Promise.resolve(直接量)
直接量
有返回值
async
await
async/await
异步流程控制
apply
func.apply(this, [arg1, arg2])
call
func.call(this, arg1, arg2);
bind
绑定后返回一个函数,待后续调用。

多次 bind() 是无效的,更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。
绑定后立即执行
绑定后非立即执行
apply/call
都是为了改变函数执行上下文



1. 改变this指针,第一个参数都是this要指向的对象,也就是想指定的上下文;



2. 借用其他对象的方法





下面就借用一道面试题,来更深入的去理解下 apply 和 call 。



定义一个 log 方法,让它可以代理 console.log 方法,常见的解决方法是:



function log(msg) {

  console.log(msg);

}

log(1);    //1

log(1,2);    //1

上面方法可以解决最基本的需求,但是当传入参数的个数是不确定的时候,上面的方法就失效了,这个时候就可以考虑使用 apply 或者 call,注意这里传入多少个参数是不确定的,所以使用apply是最好的,方法如下:



function log(){

  console.log.apply(console, arguments);

};

log(1);    //1

log(1,2);    //1 2

接下来的要求是给每一个 log 消息添加一个"(app)"的前辍,比如:



log("hello world");    //(app)hello world

该怎么做比较优雅呢?这个时候需要想到arguments参数是个伪数组,通过 Array.prototype.slice.call 转化为标准数组,再使用数组方法unshift,像这样:





function log(){

  var args = Array.prototype.slice.call(arguments);

  args.unshift('(app)');



  console.log.apply(console, args);

};
回调函数中的this指向window对象
setTimeout不止两个参数,后面的参数可作为回调参数的入参
HTML5中已经将最小执行时间统一为4ms
所谓的立即执行 0
来看一个网上很流行的例子:

1. document.querySelector('#one input').onkeydown = function() {   



  document.querySelector('#one span').innerHTML = this.value;   



};   



2. document.querySelector('#second input').onkeydown = function() {   



  setTimeout(function() {   



    document.querySelector('#second span').innerHTML = document.querySelector('#second input').value;   }, 0);



};



第一个仅会输出最后一个字符前面的字符,后漏掉最后输入的那个字符,而第二个加了settimeout会准确输出
settimeout
采用定时器需要动用红黑树。





setTimeout(function(){

  // statement

}, 0);



上面的代码表示立即执行。



本意是立刻执行调用函数,但事实上,上面的代码并不是立即执行的,这是因为setTimeout有一个最小执行时间,当指定的时间小于该时间时,浏览器会用最小允许的时间作为setTimeout的时间间隔,也就是说即使我们把setTimeout的延迟时间设置为0,被调用的程序也没有马上启动。



不同的浏览器实际情况不同,IE8和更早的IE的时间精确度是15.6ms。不过,随着HTML5的出现,在高级版本的浏览器(Chrome、ie9+等),定义的最小时间间隔是不得低于4毫秒,如果低于这个值,就会自动增加,并且在2010年及之后发布的浏览器中采取一致。



所以说,当我们写为 setTimeout(fn,0) 的时候,实际是实现插队操作,要求浏览器“尽可能快”的进行回调,但是实际能多快就完全取决于浏览器了。

著作权归作者所有。

商业转载请联系作者获得授权,非商业转载请注明出处。

原文: http://ghmagical.com/article/page/id/H61NOVU0RZ9Y © ghmagical.com著作权归作者所有。

商业转载请联系作者获得授权,非商业转载请注明出处。

原文: http://ghmagical.com/article/page/id/H61NOVU0RZ9Y © ghmagical.com
实现与settimeout大体一致,只是该方法多了重复执行的过程
setInterval
内部由链表实现
setImmediate
内部由数组实现,时间复杂度为O(1)
process.nextTick
内部由红黑树实现,时间复杂度为O(lg(n))
优先级对比: process.nextTick > setImmediate > setTimeout = setInterval , idle观察者优于IO观察者,IO观察者优于check观察者, process.nextTick 属于idle观察者,setImmediate属于check观察者
非IO异步Api
读取函数内部变量
让这些变量始终保持在内存中
栗子1:



  function f1(){

    var n=999;



    nAdd=function(){n+=1}



    function f2(){

      alert(n);

    }

    return f2;

  }



  var result=f1();



  result(); // 999



  nAdd();



  result(); // 1000



原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。



栗子2: 



for( var i = 0; i < 5; i++ ) {

	setTimeout(() => {

		console.log( i );

	}, 1000 * i)

}

// 结果为5个5,每秒输出一个



根据作用域的工作原理,实际情况是尽管循环中的五个函数是在各个迭代中分别定义的,

但是它们都被封闭在一个共享的全局作用域中,因此实际上只有一个 i。



栗子3: 

for (var i = 1; i <= 5; i++) {

    let j = i;  // 输出结果正常

    setTimeout(function timer() {

        console.log(j);

    },j*1000);

}



栗子4:



for (var i = 1; i <= 5; i++) {

    var j = i; // 输出结果没变

    setTimeout(function timer() {

        console.log(j);

    },j*1000);

}



栗子5:

for( var i = 0; i < 5; i++ ) {

	((j) => {

		setTimeout(() => {

			console.log( j );

		}, 1000 * j)

	})(i)	

}



栗子6: 



function test(){

     for (let i=0; i<5; i++) {  // 正常

        setTimeout( function timer() {

            console.log(new Date(),i);

        }, i*1000 );

    }

 //   console.log("end",new Date(),i);  //因为变量作用域的问题,这里会报i 不存在,未声明    

}
用处
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大, 所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。 解决方法是,在退出函数之前,将不使用的局部变量全部删除。
闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
注意
闭包
闭包就是能够读取其他函数内部变量的函数。



栗子1: 

    getNameFunc返回的匿名函数不属于getNameFunc的成员变量,也就无法访问其父级的变量。

   var name = "The Window";



  var object = {

    name : "My Object",

    getNameFunc : function(){

      return function(){

        return this.name;

      };

    }

  };



  alert(object.getNameFunc()());



栗子2:



     var name = "The Window";

  var object = {

    name : "My Object",

    getNameFunc : function(){

      var that = this;

      return function(){

        return that.name;

      };

    }

  };



  alert(object.getNameFunc()());
express
koa
常用框架
同步代码(包括promise的构造函数) -> promise.then -> setTimeout , 实际上promise.then内部会根据系统来判断,若系统支持setImmediate则直接执行该函数,否则执行process.nextTick
优先级对比