Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浅读-深入浅出Nodejs #41

Open
HerryLo opened this issue Apr 19, 2023 · 0 comments
Open

浅读-深入浅出Nodejs #41

HerryLo opened this issue Apr 19, 2023 · 0 comments
Assignees
Labels
Blog 文章

Comments

@HerryLo
Copy link
Member

HerryLo commented Apr 19, 2023


date: 2023-04-01 13:40

浅读-深入浅出Nodejs

原文链接

原书作者:朴灵 https://book.douban.com/subject/25768396/

这次算是重读 深入浅出Nodejs,了解到很多之前忽略的细节,收获蛮多,这次顺便将其记录分享,对学习和了解Nodejs有及其大的帮助。

1.Nodejs

  • _事件驱动、_非阻塞IO,一个开源和跨平台的 JavaScript 运行时环境
  • 异步I/O:每个调用之间无须等待之前的I/O调用结束;
  • 事件:轻量级、松耦合、只关注事务点;
  • Node擅长I/O密集型的应用场景;(适合面向网络,不适合慢IO,如读磁盘)

2.模块

  • CommonJS的模块规范。Node中引入模块三步:路径分析、文件定位、编译执行;
  • 不论是核心模块还是文件模块,require()方法对相同模块的二次加载都一律采用缓存优先的方式,这是第一优先级的。不同之处在于核心模块的缓存检查先于文件模块的缓存检查;

9F250D83-1940-4518-B757-8405262F1F2F.png

3.异步IO

  • 单线程异步编程,极大的利用资源,避免单线程阻塞,更好的利用CPU;
  • 完美的异步I/O应该是应用程序发起非阻塞调用,无须通过遍历或者事件唤醒等方式轮询,可以直接处理下一个任务,只需在I/O完成后通过信号或回调将数据传递给应用程序即可;
  • 注意:Nodejs单线程仅仅只是JavaScript执行在单线程中。在Node中,无论是*nix还是Windows平台,内 部完成I/O任务的另有线程池;

Node异步I/O

  • 事件循环:Node便会创建一个类似于while(true)的循环,每执行一次循环体的过程我们称为Tick。每个Tick的过程就是查看是否有事件待处理,如果有,就取出事件及其相关的回调函数。如果存在关联的回调函数,就执行它们。然后进入下个循环,如果不再有事件处理,就退出进程;
  • 观察者:在每个Tick的过程中,如何判断是否有事件需要处理呢?这里必须要引入的概念是观察者。每个事件循环中有一个或者多个观察者,而判断是否有事件要处理的过程,就是向这些观察者询问是否有要处理的事件;

事件循环是一个典型的生产者/消费者模型。异步I/O、网络请求等则是事件的生产者,源源不断为Node提供不同类型的事件,这些事件被传递到对应的观察者那里,事件循环则从观察者那里取出事件并处理;
6EAE61B7-ED3B-4188-B801-EABD9B5EFC3D.png

非I/O异步API

setTimeout()setInterval()setImmediate()process.nextTick()
setTimeout

  • setTimeout()setInterval()与浏览器中的API是一致的,分别用于单次和多次定时执行任务。
  • 调用setTimeout()或者setInterval()创建的定时器会被插入到定时器观察者内部的一个红黑树中。每次Tick执行时,会从该红黑树中迭代取出定时器对象,检查是否超过定时时间,如果超过,就形成一个事件,它的回调函数将立即执行。

E1F03D22-5113-4df2-8972-1F469F6E8242.png

process.nextTick

  • 每次调用process.nextTick()方法,只会将回调函数放入队列中,在下一轮Tick时取出执行;

setImmediate

  • setImmediate() 参数传入的任何函数都是在事件循环的下一个迭代中执行的回调;
  • 延迟 0 毫秒的 setTimeout() 回调与 setImmediate() 非常相似。 执行顺序取决于各种因素,但是它们都会在事件循环的下一个迭代中运行;

区别

  • 传给 process.nextTick() 的函数会在事件循环的当前迭代中(当前操作结束之后)被执行。 这意味着它会始终在 setTimeoutsetImmediate 之前执行。
  • 同步和异步的区别。也就是说,是否是同步还是异步,关注的是任务完成时消息通知的方式。由调用方盲目主动问询的方式是同步调用,由被调用方主动通知调用方任务已完成的方式是异步调用;
  • 是否是阻塞还是非阻塞,关注的是接口调用(发出请求)后等待数据返回时的状态。被挂起无法执行其他操作的则是阻塞型的,可以被立即「抽离」去完成其他「任务」的则是非阻塞型的;

参考文章:

4.异步编程

  • 优点:利用事件循环的方式,JavaScript线程像一个分配任务和处理结果的大管家,I/O线程池里的各个I/O线程都是小二,负责兢兢业业地完成分配来的任务,小二与管家之间互不依赖,保持整体高效率;
  • 缺点:这个模型的缺点则在于管家无法承担过多的细节性任务,如果承担太多,则会影响到任务的调度;(CPU密集型是弱点)

异步编程解决方案

  • 事件发布/订阅模式;
  • Promise/Deferred模式;
  • 流程控制库;

异步并发控制

  • 异步调用的并发限制在不同场景下的需求不同:非实时场景下,让超出限制的并发暂时等待执行可以满足需求;(一个队列来控制并发量,如果当前活跃(指调用发起但未执行回调)的异步调用量小于限定值,从队列中取出执行。如果活跃调用达到限定值,调用暂时存放在队列中。❑ 每个异步调用结束时,从队列中取出新的异步调用执行)

5.内存控制

  • V8堆内存的最大值在64位系统上为1464 MB, 32位系统上则为732 MB;
  • 在V8中,主要将内存分为新生代和老生代两代。新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象;
  • Node的内存构成主要由通过V8进行分配的部分和Node自行分配的部分,受V8的垃圾回收限制的主要是V8的堆内存。(利用堆外内存可以突破内存限制的问题,如 Buffer
  • 内存泄漏原因:缓存、队列消费不及时、作用域未释放;
  • 操作大文件可以使用stream模块用于处理;

6.理解Buffer

  • Buffer主要用于操作字节;
  • 小而频繁的Buffer操作时,采用slab的机制进行预先申请和事后分配,使得JavaScript到操作系统之间不必有过多的内存申请方面的系统调用;
  • 大块的Buffer对象,直接使用C++层面提供的内存;

7.网络编程

Nodejs提供的netdgramhttptls等模块,让面向网络编程更加便捷。
通过http模块即可快速搭建Web服务器;网络是轻IO操作,再配合上Nodejs异步IO,Nodejs在面向网络编程方面能维持的并发量和QPS都是不容小觑的;

8.构建Web应用

告诉开发者如何通过Nodejs构建一个合格的网络应用服务。

  1. 使用Nodejs配合http模块搭建路由服务;
  2. 解析、使用和存储Cookie;
  3. Session使用和存储,包括如何高效管理Session;
  4. 通过网络缓存避免带宽浪费;
  5. 数据上传需要注意点:大文件使用流式解析、限制上传内容的大小、避免CSRF攻击加强校验;
  6. 中间件的理念和实现;

9.玩转进程

  1. 服务模型:同步——>复制进程——>多线程——>事件驱动;
  2. child_process模块搭建多进程;

感谢 朴灵 写出这样的好书,并且分享给开发者。

@HerryLo HerryLo self-assigned this Oct 25, 2023
@HerryLo HerryLo added the Blog 文章 label Oct 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Blog 文章
Projects
None yet
Development

No branches or pull requests

1 participant