引言
本着对js这门语言的喜爱,我阅读了node.js。希望阅读过程中对其有所收获。以此共勉
Node简介 – 第一章
我惊奇于Node.js竟然是一门这么年轻的语言,2009年就诞生了
选择js的原因
高性能web服务器有两个要点:事件驱动、非阻塞IO
js有到高性能、符合事件驱动、没有历史包袱(学习难度不大,没有很多历史遗留下来的IO阻塞)
Node给JavaScript带来的意义
除了HTML、WebKit和显卡这些UI相关技术没有支持外,Node的结构与Chrome十分相似。
在Node中,js不再局限于浏览器本身,可以访问本地文件,可以搭建WebSocket服务器端,可以连接数据库,可以如Web Workers一样玩转多进程。
这些特性促使了桌面应用程序也可以用html、css、js来实现
异步IO
这个是经典的异步io的请求。
在Node中,绝大多数操作都是异步请求,以节省操作的事件。
事件与回调函数
事件的编程方式具有轻量级、松耦合、只关注事务点等优势,但是在多个异步任务的场景下,事件与事件之间各自独立,如何协作是一个问题。
前面可以看到,回调函数无处不在。这是因为在JavaScript中,我们将函数作为第一等公民来对待,可以将函数作为对象传递给方法作为实参进行调用。(js独特的函数可以作为参数转递)。
回调函数也是最好的接受异步调用返回数据的方式。
我这里补一下回调函数的知识(目前我还是低级开发,用到自定义的回调函数还是比较少的🤦)
回调函数的一下解释
回调函数即别人调用了这个函数,即函数作为参数传入另一个函数。
1. 自己定义的函数
2. 自己没调用
3. 函数最终执行了
单线程
优点:单线程的最大好处是不用像多线程编程那样处处在意状态的同步问题,这里没有死锁的存在,也没有线程上下文交换所带来的性能上的开销。
缺点:
- 无法利用多核CPU。
- 错误会引起整个应用退出,应用的健壮性值得考验。
- 大量计算占用CPU导致无法继续调用异步I/O。
问题
像浏览器中JavaScript与UI共用一个线程一样,JavaScript长时间执行会导致UI的渲染和响应被中断。在Node中,长时间的CPU占用也会导致后续的异步I/O发不出调用,已完成的异步I/O的回调函数也会得不到及时执行。
解决
Web Workers能够创建工作线程来进行计算,以解决JavaScript大计算阻塞UI渲染的问题。工作线程为了不阻塞主线程,通过消息传递的方式来传递运行结果,这也使得工作线程不能访问到主线程中的UI。
所以有些同学在其他地方的开发看到什么渲染进程、其他进程,就会疑惑js不是单线程的吗,为什么会有这么多个线程。这里就可以得到答案啦。
子进程的出现,意味着Node可以从容地应对单线程在健壮性和无法利用多核CPU方面的问题。通过将计算分发到各个子进程,可以将大量计算分解掉,然后再通过进程之间的事件消息来传递结果,这可以很好地保持应用模型的简单和低依赖。通过Master-Worker的管理方式,也可以很好地管理各个工作进程,以达到更高的健壮性。
跨平台
我们经常可以看到前端项目的有点就是跨平台,无论是移动端,还是桌面端。
多个平台不同语言重新开发应用确实是挺浪费时间成本和资源的。
node的跨平台得益于操作系统与Node上层模块系统之间构建
了一层平台层架构,即libuv。
libuv已经成为许多系统实现跨平台的基础组件
Node的应用场景
-
适用于IO密集型业务
-
密集CPU使用的情况下
-
面对普通阻塞I/O
可以适当调整和分解大型运算任务为多个小任务,使得运算能够适时释放,
不阻塞I/O调用的发起,这样既可同时享受到并行异步I/O的好处,又能充分利用CPU。(避免单线程引起的弊端) -
对于长时间运行的计算
如果这长期时间的计算比普通io阻塞要花费更多的时间的话,我们可以采用一下措施。(这种情况下一般采用多线程,但是Node没有多线程)- Node可以通过编写C/C++扩展的方式更高效地利用CPU,将一些V8不能做到性能极致的地方通过C/C++来实现。
- 将一部分Node进程当做常驻服务进程用于计算,然后利用进程间的消息来传递结果,将计算与I/O分离,这样还能充分利用多CPU。
可见面对这类问题的情况下,如何合理地调度才是关键。
-
分布式应用
分布式应用往往是高效利用并行I/O的例子。Node高效利用并行I/O的过程,也是高效使用数据库的过程。