• 学习笔记—Node的基本概念


    日常的学习笔记,包括 ES6、Promise、Node.js、Webpack、http 原理、Vue全家桶,后续可能还会继续更新 Typescript、Vue3 和 常见的面试题 等等。


    Node的基本概念

    什么是Node?

    Node.js是一个基于 Chrome V8 引擎的JavaScript运行环境(runtime),Node不是一门语言是让js运行在后端的运行时,并且不包括javascript全集,因为在服务端中不包含DOM和BOM,Node也提供了一些新的模块例如http、fs模块等。Node.js 使用了事件驱动、非阻塞式 I/O 的模型,使其轻量又高效并且Node.js 的包管理器 npm,是全球最大的开源库生态系统。到此我们已经对node有了简单的概念。

    Node的高并发

    Node在处理高并发,I/O密集场景有明显的性能优势。

    • 高并发,是指在同一时间并发访问服务器。
    • I/O密集指的是文件操作、网络操作、数据库,相对的有CPU密集,CPU密集指的是逻辑处理运算、压缩、解压、加密、解密。

    Web主要场景就是接收客户端的请求读取静态资源和渲染界面,所以Node非常适合Web应用的开发。

    说到高并发,肯定就会想起多线程。那么多线程和高并发之间的关系和区别又是什么呢?

    多线程

    首先我们先来了解一下什么是多线程

    多线程示意图

    后端语言(包括Java、C++等)存在一个线程池,每发送一次请求,线程池都会分配一个线程给服务器,用来处理请求,以此类推。因为多线程语言的特点是同步请求,所以在多线程发送请求时,可能会存在单个线程阻塞的情况,需要等待当前这个线程的任务处理完毕后,才会释放线程并放回到线程池,方便下一批任务的使用。当前线程数超过线程池最大可分配数量时,可能就会出现等待的情况。

    • 多线程优点:可以高效高速的处理多个api请求图片压缩、大量计算 等...),属于cpu密集型

    • 多线程缺点不安全性,假设我们有多个线程需要对数据库同一个资源进行操作(例如对同一个数据进行修改),就会出现数据安全性的问题 [需要对资源进行加锁操作]。

    多线程并非一起做某一件事,靠的是切换上下文(分时),所以多线程会浪费一些资源

    关于多线程的具体概念,可以去查阅相关的资料。

    高并发

    高并发是单线程的一个概念。

    • 高并发优点:不需要开启多个线程,节省资源
    • 高并发缺点不适合做复杂操作,如果需要做复杂操作,可以开启子进程。

    Node是多线程的,但是其主线程是单线程。所以我们一直都说,Node其实是单线程语言。

    同步异步和阻塞非阻塞

    • 同步就是在执行某段代码时,代码没有得到返回之前,其他代码无法执行,当得到了返回值后可以继续执行其他代码。
    • 异步就是在执行某段代码时,代码不会立即得到返回结果,可以继续执行其他代码,返回值通过回调来获取。

    关于同步阻塞与异步非阻塞,可以参考我之前的文章。

    Node中的EventLoop

    Node中EventLoop原理

    • 1.我们写的js代码会交给v8引擎进行处理。
    • 2.代码中可能会调用nodeApi,node会交给libuv库处理
    • 3.libuv通过阻塞i/o和多线程实现了异步io。
    • 4.通过事件驱动的方式,将结果放到事件队列中,最终交给我们的应用。
        本阶段执行已经被 setTimeout() 和 setInterval() 的调度回调函数。
       ┌───────────────────────────┐
    ┌─>│           timers          │ 
    │  └─────────────┬─────────────┘
    |   执行延迟到下一个循环迭代的 I/O 回调。
    │  ┌─────────────┴─────────────┐
    │  │     pending callbacks     │
    │  └─────────────┬─────────────┘
    |   仅系统内部使用。
    │  ┌─────────────┴─────────────┐
    │  │       idle, prepare       │
    │  └─────────────┬─────────────┘      
    |  检索新的I/O事件;执行与 I/O相关的回调    ┌───────────────┐
    │  ┌─────────────┴─────────────┐      │   incoming:   │
    │  │           poll            │<─────┤  connections, │
    │  └─────────────┬─────────────┘      │   data, etc.  │
    │  setImmediate() 回调函数在这里执行。   └───────────────┘
    │  ┌─────────────┴─────────────┐      
    │  │           check           │
    │  └─────────────┬─────────────┘
    |  一些关闭的回调函数
    │  ┌─────────────┴─────────────┐
    └──┤      close callbacks      │  
       └───────────────────────────┘
    

    这里每一个阶段都对应一个事件队列,当event loop执行到某个阶段时会将当前阶段对应的队列依次执行。当该队列已用尽或达到回调限制,事件循环将移动到下一阶段。

    process.nextTick() 从技术上讲不是事件循环的一部分。优先级高于微任务

    poll阶段:

    1. 检测Poll队列中是否为空,如果不为空则执行队列中的任务,直到超时或者全部执行完毕。

    2. 执行完毕后检测setImmediate队列是否为空,如果不为空则执行check阶段,如果为空则等待时间到达。时间到达后回到timer阶段

    3. 等待时间到达是可能会出现新的callback,此时也在当前阶段被清空


    本篇文章由莫小尚创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。
    您也可以关注我的 个人站点博客园掘金,我会在文章产出后同步上传到这些平台上。
    最后感谢您的支持!

  • 相关阅读:
    优化网站性能的14条准则
    单元测试
    无配置wcf Host
    .net 4.0
    Java 7 resources
    关于重用
    用GMaven plugin更好地编译系统
    关于系统分层的自问自答
    UBIQUITOUS LANAGUAGE
    用Groovy方式实现接口便于单元测试和协作开发
  • 原文地址:https://www.cnblogs.com/moxiaoshang/p/15501994.html
Copyright © 2020-2023  润新知