在学习Node的过程当中,咱们要了解一些基础概念。什么是Node他又解决了哪些问题以及Node的特色。包括傻傻分不清的进程和线程,同步与异步,阻塞和非阻塞,以及Node中核心的(Event Loop)事件环的概念。javascript
Node.js是一个基于 Chrome V8 引擎的JavaScript运行环境(runtime),Node不是一门语言是让js运行在后端的运行时,而且不包括javascript全集,由于在服务端中不包含DOM
和BOM
,Node也提供了一些新的模块例如http,fs模块等。Node.js 使用了事件驱动
、非阻塞式 I/O
的模型,使其轻量又高效而且Node.js 的包管理器 npm,是全球最大的开源库生态系统。事件驱动与非阻塞IO后面咱们会一一介绍。到此咱们已经对node有了简单的概念。java
Node在处理高并发,I/O密集场景有明显的性能优点node
Web主要场景就是接收客户端的请求读取静态资源和渲染界面,因此Node很是适合Web应用的开发。ajax
进程是操做系统分配资源和调度任务的基本单位,线程是创建在进程上的一次程序运行单位,一个进程上能够有多个线程。数据库
因而可知浏览器是多进程的,而且从咱们的角度来看咱们更加关心浏览器渲染引擎npm
渲染引擎内部是多线程的,内部包含两个最为重要的线程ui线程和js线程。这里要特别注意ui线程和js线程是互斥的,由于JS运行结果会影响到ui线程的结果。ui更新会被保存在队列中等到js线程空闲时当即被执行。后端
javascript在最初设计时设计成了单线程,为何不是多线程呢?若是多个线程同时操做DOM那岂不会很混乱?这里所谓的单线程指的是主线程是单线程的,因此在Node中主线程依旧是单线程的。咱们来张图看看单线程和多线程promise
单线程特色是节约了内存,而且不须要在切换执行上下文。并且单线程不须要管锁的问题,这里简单说下锁的概念。例以下课了你们都要去上厕所,厕所就一个,至关于全部人都要访问同一个资源。那么先进去的就要上锁。而对于node来讲。下课了就一我的去厕所,因此免除了锁的问题!浏览器
setTimeout(function(){
console.log(1)
})
setTimeout(function(){
console.log(2)
})
setTimeout(function(){
console.log(3)
})
复制代码
当设置定时器时,会将定时器对应的回调函数依次的放到队列中,执行时按照放置的顺序依次执行。tomcat
function stack(){
console.log(1);
fn1();
function fn1(){
console.log(2);
fn2();
function fn2(){
console.log(3)
}
}
}
stack();
复制代码
咱们能够看到js是在全局的上下文中执行的,调用栈入栈的顺序是stack->fn1->fn2,看成用域销毁时先须要先销毁fn2->fn1->stack
整个的这种运行机制又称为Event Loop(事件循环)
咱们先来张图看看node是如何工做的
在libuv内部有这样一个事件环机制。在node启动时会初始化事件环
┌───────────────────────┐
┌─>│ timers(计时器) │
| | 执行setTimeout以及 |
| | setInterval的回调。 |
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks |
│ | 处理网络、流、tcp的错误 |
| | callback |
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
| | node内部使用 |
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐ ┌───────────────┐
│ │ poll(轮询) │ │ incoming: │
| | 执行poll中的i/o队列 | <─────┤ connections, │
| | 检查定时器是否到时 | │ data, etc. |
│ └──────────┬────────────┘ └───────────────┘
│ ┌──────────┴────────────┐
│ │ check(检查) │
| | 存放setImmediate回调 |
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks |
│ 关闭的回调例如 |
| sockect.on('close') |
└───────────────────────┘
复制代码
这里每个阶段都对应一个事件队列,当event loop执行到某个阶段时会将当前阶段对应的队列依次执行。当队列执行完毕或者执行的数量超过上线时,会转入下一个阶段。这里咱们重点关注poll阶段
两者很是类似,可是两者区别取决于他们何时被调用.
setTimeout(function timeout () {
console.log('timeout');
},0);
setImmediate(function immediate () {
console.log('immediate');
});
复制代码
nextTick并不属于事件循环的某个阶段,他的执行方式是在各个阶段切换的中间执行,来段恶心的代码
setImmediate(function(){
console.log(1);
process.nextTick(function(){
console.log(2);
});
});
process.nextTick(function(){
console.log(3);
setImmediate(function(){
console.log(4);
})
});
// 3 1 4 2
复制代码
这里就不解释了,若是你懂了,说明就明白nextTick的执行时机了!(nextTick不要递归调用,不然后面阶段的callback将没法执行)
任务可分为宏任务和微任务
process.nextTick > promise.then > setTimeout > setImmediate
复制代码
经过上面的学习咱们知道了任务的执行顺序,要注意的是Promise.then方法被定义在了nextTick以后执行
同步异步取决于被调用者,阻塞非阻塞取决于调用者
到此咱们详细的解说了一下node中的概念,喜欢的点个赞吧^_^! 支持个人能够给我打赏哈