node的知识点

(一)Node能够解决什么问题?
1)Node的首要目标是提供一种简单的,用于创建高性能服务器的开发工具
2)对比Java和Php的实现方式,Web服务器的瓶颈在于并发的用户量
3)Node在处理高并发,I/O密集场景有明显的性能优势
  1)高并发,是指在同一时间并发访问服务器
  2)I/O密集指的是文件操作、网络操作、数据库
  3)与I/O密集相对的是CPU密集,CPU密集指的是逻辑处理运算、压缩、解压、加密、解密
4)Web主要场景就是接收客户端的请求,读取静态资源和渲染界面,所以Node非常适合Web应用的开发

 

2)Node出现的背景
为了解决Web服务器的高并发性能问题
1)什么性能问题?
  

  1)缩短发送到响应的时长
    1)发送请求快一点
    不能控制(客户端网速决定)
    2)响应快一点
    可以控制(服务器带宽提高, CDN加速...)
    3)服务器处理请求任务快一点
    可以控制(优秀的程序员)
    4)服务器从磁盘读取/写入数据到数据库快一点
      所有项目后期都会遇到的瓶颈
    不能控制(磁盘的读取速度有上限)

....
  2)传统服务器的运作流程
    多线程
    发送一个请求就开启一条线程
    举例: 饭店服务员
    需要大量的资源支持
2)Ryan Dahl(瑞安·达尔)尝试过用Ruby, c, Lua去解决, 但都因为语言自身的各种限制而一一失败
江山易改,本性难移
语言历史包袱太重, 船大难掉头
各种语言的思想都根深蒂固, 生态没法轻易改变
3)V8引擎的出现
  渐渐摸索到解决问题的钥匙
  事件驱动
  异步I/O

 

3)V8引擎的出现
  1)什么是V8引擎?
  一款专门对JavaScript语言进行解释和执行的流程虚拟机
  比如把V8引擎嵌入到浏览器中,那么我们写的JavaScript代码就会被浏览器所执行;那么如果把V8引擎嵌入到NodeJS环境下,那么我们写的JavaScript代码就会被服务器所执行
  V8引擎嵌入到不同的宿主环境中时,可以把JavaScript语言应用到不同的多领域中
  2)起初的作用?
  用于Chrome浏览器解析js脚本
  比如: 发送HTTP请求给服务器, 响应服务器端返回的HTTP请求
  3)V8引擎的优势?
    1)强大的编译和快速的执行效率
    运用了大量的算法和奇技淫巧
    2)性能非常好, 它的执行效率远超Python, Ruby等其它脚本语言
    3)历史包袱轻, 没有同步I/O
    4)强大的事件驱动机制
    4)Node的诞生 Ryan Dahl(瑞安·达尔)修改V8引擎的内核, 把它用在了服务器开发, 经过修改后的这样一套东西就被称为Node.js

 

(三) Node.js简介
1)什么是Node.js
  1)Node.js是一个基于 Chrome V8 引擎的JavaScript运行环境(runtime)
  1)Node不是一门语言,而是一个开发工具,让JS运行在后端
  2)Node不包含JavaScript全集,在服务器端没有DOM和BOM
  3)Node也提供了一系列新的模块,例如:http,fs模块等
  4)Node之前, js代码只能运行在客户端, 最多只能在浏览器内翻江倒海
  5)Node之后, js代码可以和操作系统(Mac OS, windows, Linux...)交互, 战场从浏览器延伸到了服务器
  6)版本变化
  一开始叫Web.js, 目的就是用于写高性能Web服务器的
  越写越大, 形成生态(服务器开发, 各种框架的依赖...), 改名为Node.js
  Node: 节点, Node的开源团队希望它像节点一样可以不断扩展, 壮大
  图示

  

 

2)功能类似的其他后端语言

  PHP、JSP、Python、Ruby
  和系统进行交互
3)和其它后端语言的区别
  1)Node.js不是一种独立的语言
    1)PHP, JSP,.... 既是语言, 也是平台
    2)Node.js用JavaScript进行编程, 运行平台是包装后的js引擎(V8)
  2)轻量级架构
    1)java,php,.net都需要运行在服务器上,apache,tomat,nginx,IIS
    2)Node.js不用架设在任何服务器软件之上
    3)用最小的硬件成本, 达到更高的并发, 更优的处理性能
    4)Node.js 使用了事件驱动、非阻塞式 I/O 的模型,使其轻量又高效;并且Node.js 的包管理器 npm,是全球最大的开源库生态系统

2)进程与线程 1)概念
  1)进程是操作系统分配资源和调度任务的基本单位
  2)线程是建立在进程上的一次程序运行单位,一个进程上可以有多个线程
 2)浏览器是单线程还是多线程?
  1)图示
    

  3)浏览器是多线程的,我们更关注的是浏览器的渲染引擎
3)渲染引擎
  1)渲染引擎内部是多线程的,内部包含两个最为重要的线程ui线程和js线程
  2)ui线程和js线程是互斥的,因为JS运行结果会影响到ui线程的结果
  3)ui更新会被保存在队列中等到js线程空闲时立即被执行
4)JS是单线程的
  1)JS在最初设计时就设计成了单线程,因为当时是用于UI绘制,多个线程同时操作DOM会很混乱
  2)这里所说的单线程指的是主线程是单线程的,所以在Node中主线程依旧是单线程的
  3)其他线程
    1)浏览器事件触发线程(用来控制事件循环,存放setTimeout、浏览器事件、ajax的回调函数)
    2)定时触发器线程(setTimeout定时器所在线程)
    3)异步HTTP请求线程(ajax请求线程

  4)补充
    1)单线程特点是节约了内存,并且不需要再切换执行上下文
    2)而且单线程不需要管锁的问题
    例如:下课了大家都要去上厕所,厕所就一个大号,相当于所有人都要访问同一个资源,那么先进去的就要上锁
    而对于node来说,下课了就一个人去厕所,所以免除了锁的问题

  5)查看线程
    右击 任务栏 -->任务管理器 --> 进程



3)事件循环
  1)图示

  2)运行原理
    1)所有同步任务都在主线程上执行,形成一个执行栈
    2)主线程之外,还存在一个任务队列;只要异步任务有了运行结果,就在任务队列之中放置一个事件
    3)一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,将队列中的事件放到执行栈中依次执行
    4)主线程从任务队列中读取事件,这个过程是循环不断的
4)Node运行过程
  1)图示

   2)运行过程
    1)我们写的js代码会交给v8引擎进行处理
    2)代码中可能会调用nodeApi,node会交给libuv库处理
    3)libuv通过阻塞i/o和多线程实现了异步io
    4)通过事件驱动的方式,将结果放到事件队列中,最终交给我们的应用
  3)同步与异步
    同步和异步关注的是消息通知机制
    2)同步
      同步就是发出调用后,没有得到结果之前,该调用不返回,一旦调用返回,就得到返回值了
      调用者主动等待这个调用的结果
    3)异步
      异步则相反,调用者在发出调用后这个调用就直接返回了,所以没有返回结果
      当一个异步过程调用发出后,调用者不会立刻得到结果,而是调用发出后,被调用者通过状态、通知或回调函数处理这个调用
  4)阻塞与非阻塞
    阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态
    2)阻塞调用
      指调用结果返回之前,当前线程会被挂起
      调用线程只有在得到结果之后才会返回
    3)非阻塞调用
      在不能立刻得到结果之前,该调用不会阻塞当前线程
2)Node.js的特点
  1)单线程
    1)优势
    减少了内存开销(操作系统完全不再有线程创建、销毁的时间开销)
    Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程
    2)劣势
    如果某一个事情,进入了,但是被I/O阻塞了,整个线程就阻塞了
    如果一个人把Node.js主线程搞崩溃,全部崩溃(但很难搞崩溃)
  2)非阻塞I/O
    1)基本概念?
    当在访问数据库取得数据的时候,需要一段时间。在传统的单线程处理机制中,在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库返回结果,才能执行后面的代码。也就是说,I/O阻塞了代码的执行,极大地降低了程序的执行效率
  不会傻等I/O语句结束,而会执行后面的语句
  Node.js中采用了非阻塞型I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率
  当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理
  阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行运行操作,这个线程的CPU核心利用率永远是100%
  所以,这是一种特别有哲理的解决方案:与其人多,但是好多人闲着;还不如一个人玩命,往死里干活儿
  2)非阻塞就能解决问题了么?
    比如执行着小红的业务,执行过程中,小刚的I/O回调完成了,此时怎么办??所以要有事件驱动循环
  3)事件驱动
  1)基本概念?
    不管是新用户的请求,还是老用户的I/O完成,都将以事件方式加入事件环,等待调度
  2)运作流程?

    1)在Node中,客户端请求建立连接,提交数据等行为,会触发相应的事件
    2)在Node中,在一个时刻,只能执行一个事件回调函数, 但是在执行一个事件回调函数的中途,可以转而处理其他事件(比如,又有新用户连接了),然后返回继续执行原事件的回调函数,这种处理机制,称为“事件环”机制。
    3)当某一个事件发生的时候,就去执行回调函数。执行完毕之后,再去找到事件循环当中找一个新的事件进行来
    4)Node.js当中所有的I/O都是异步的, 都是回调函数套回调函数

 

 

3)实践2
  1)模块标识
    当我们使用require()引入外部模块时,使用的就是模块标识,我们可以通过模块标识来找到指定的模块
    比如: let myFunc = require("./js/myFunc");
  2)思考: export和require怎么来的?
    1)错误答案: 全局变量
      1)window不是Node中的全局对象
      2)Node中有一个全局对象global, 作用和window类似
    2)正确答案: 函数参数
      1)函数的标识: arguments
        获取函数的所有实参
      2)获取函数自身 arguments.callee
        返回函数本身
3)node文件组成剖析
  1)当node在执行模块中的代码时,它会首先在代码的最顶部,添加如下代码 function (exports, require, module, __filename, __dirname) {
  2) 在代码的最底部,添加 }
  3)所以模块中的代码都是包装在一个函数中执行的,并且在函数执行的同时传递进了5个实参
    exports: 该对象用来将函数内部的局部变量或局部函数暴露到外部
    require: 用来引入外部的模块
    module: 代表的是当前模块本身, exports就是module的属性; 我们既可以使用 exports 导出,也可以使用module.exports导出
    __filename: 当前模块的完整路径
    __dirname: 当前模块所在文件夹的完整路径

posted @ 2019-07-01 00:39  疏影横斜水清浅  阅读(622)  评论(0编辑  收藏  举报