为什么使用Node.js?逐个案例教程

专注全栈大前端,爱前端整理了一批2019年最新WEB前端教学视频,不论是零基础想要学习前端还是学完在工作想要提升自己,这些资料都会给你带来帮助,从HTML到各种框架,帮助所有想要学好前端的同学,学习规划、学习路线、学习资料、问题解答。只要加入全栈大前端学习交流Q群:137503198,即可免费获取。

介绍

JavaScript的日益普及带来了很多变化,而今天的Web开发面貌却截然不同。我们现在可以在服务器上运行JavaScript以及在浏览器中执行的操作几年前很难想象,或者封装在沙盒环境中,如Flash或Java Applet。

在深入研究Node.js之前,您可能希望了解在堆栈中使用JavaScript的好处,它统一了语言和数据格式(JSON),允许您以最佳方式重用开发人员资源。由于这比JavaScript特别是Node.js更有益,我们在此不再讨论它。但是将Node合并到堆栈中是一个关键优势。

正如维基百科所说:“Node.js是Google的V8 JavaScript引擎,libuv平台抽象层和核心库的打包汇编,它本身主要用JavaScript编写。”除此之外,值得注意的是Ryan Dahl,创作者Node.js的目标是创建具有推送功能的实时网站,“受Gmail等应用程序的启发”。在Node.js中,他为开发人员提供了一个工具,用于处理非阻塞,事件驱动的I / O范例。

在基于无状态请求 - 响应范例的20多年无状态网络之后,我们终于拥有了具有实时双向连接的Web应用程序。

用一句话来说:Node.js在基于websockets的推送技术的实时Web应用程序中大放异彩。那是什么革命性的?好吧,在基于无状态请求 - 响应范例的20多年无状态网络之后,我们终于拥有了具有实时双向连接的Web应用程序,其中客户端和服务器都可以启动通信,允许它们自由地交换数据。这与典型的Web响应范例形成鲜明对比,客户端总是发起通信。此外,它都基于在标准端口80上运行的开放Web堆栈(HTML,CSS和JS)。

有人可能会争辩说,我们多年来一直以Flash和Java Applet的形式拥有这一点 - 但实际上,这些只是使用Web作为传输协议传递给客户端的沙盒环境。此外,它们是隔离运行的,通常在非标准端口上运行,这可能需要额外的权限等。

凭借其所有优势,Node.js现在在依赖其独特优势的众多知名公司的技术堆栈中发挥着关键作用。Node.js基金会已经整合了所有关于为什么企业应该在Node.js基金会的案例研究页面上找到的简短演示中考虑Node.js的最佳思考。

在这个Node.js指南中,我将不仅讨论如何实现这些优势,而且还讨论为什么你可能想要使用Node.js - 以及为什么不 - 使用一些经典的Web应用程序模型作为示例。

它是如何工作的?

Node.js的主要思想是:在面向跨分布式设备运行的数据密集型实时应用程序时,使用非阻塞,事件驱动的I / O保持轻量级和高效。

那是满口的。

它的真正含义是Node.js 不是一个将在Web开发领域占主导地位的银弹新平台。相反,它是一个满足特定需求的平台。

它的真正含义是Node.js 不是一个将在Web开发领域占主导地位的银弹新平台。相反,它是一个满足特定需求的平台。了解这一点绝对必要。您绝对不希望将Node.js用于CPU密集型操作; 实际上,将它用于繁重的计算将几乎消除其所有优点。Node真正发挥作用的地方在于构建快速,可扩展的网络应用程序,因为它能够以高吞吐量处理大量同时连接,这相当于高可扩展性。

如何在引擎盖下工作非常有趣。与传统的Web服务技术相比,每个连接(请求)产生一个新线程,占用系统RAM并最终以可用的RAM量最大化,Node.js在单线程上运行,使用非阻塞I / O调用,允许它支持事件循环中保存的数万个并发连接。

快速计算:假设每个线程可能随附2 MB内存,在具有8 GB RAM的系统上运行使我们理论上最多可以有4,000个并发连接(计算来自Michael Abernethy的文章“Just what is Node” .js?“,2011年在IBM developerWorks上发布;遗憾的是,这篇文章不再可用了),加上线程之间上下文切换成本。这就是您通常在传统的网络服务技术中处理的场景。通过避免这一切,Node.js实现了超过1M并发连接的可伸缩性级别,以及超过600k并发的websockets连接

当然,存在在所有客户端请求之间共享单个线程的问题,这是编写Node.js应用程序的潜在缺陷。首先,繁重的计算可能会阻塞Node的单个线程并导致所有客户端出现问题(稍后会详细说明),因为传入的请求将被阻塞,直到所述计算完成为止。其次,开发人员需要非常小心,不要让异常冒泡到核心(最顶层)Node.js事件循环,这将导致Node.js实例终止(有效地崩溃程序)。

用于避免冒泡到表面的异常的技术是将错误作为回调参数传递回调用者(而不是像在其他环境中那样抛出它们)。即使一些未处理的异常设法冒泡,也开发了一些工具来监视Node.js进程并执行崩溃实例的必要恢复(尽管您可能无法恢复用户会话的当前状态),最常见的是Forever模块,或者使用不同的方法与外部系统工具upstartmonit,甚至只是暴发户

NPM:节点包管理器

在讨论Node.js时,有一点绝对不应该被忽略的是内置支持使用NPM进行包管理,NPM是默认情况下每个Node.js安装的工具。NPM模块的概念与Ruby Gems非常相似:一组公开可用的可重用组件,可通过在线存储库轻松安装,具有版本和依赖关系管理。

可以在npm网站上找到已打包模块的完整列表,也可以使用自动与Node.js一起安装的npm CLI工具进行访问。模块生态系统对所有人开放,任何人都可以发布自己的模块,该模块将列在npm存储库中。

今天一些最有用的npm模块是:

表达 - Express.js-或简单表达 - 一个受Sinatra启发的Node.js Web开发框架,以及当今大多数Node.js应用程序的事实标准。

hapi - 一个非常模块化且易于使用的以配置为中心的框架,用于构建Web和服务应用程序

connect - Connect是Node.js的可扩展HTTP服务器框架,提供了一系列称为中间件的高性能“插件”; 作为Express的基础。

socket.iosockjs - 今天两个最常见的websockets组件的服务器端组件。

帕格(以前称为Jade) - 受HAML启发的流行模板引擎之一,Express.js中的默认值。

mongodbmongojs - MongoDB包装器,为Node.js中的MongoDB对象数据库提供API。

redis - Redis客户端库。

lodash(下划线,lazy.js) - JavaScript实用程序带。Underscore发起了游戏,但被其两个对手之一推翻,主要是因为更好的性能和模块化实施。

永远 - 可能是确保给定节点脚本连续运行的最常用实用程序。在遇到任何意外故障时,将Node.js进程保持在生产状态。

bluebird - 功能齐全的Promises / A +实现,性能非常出色

moment - 用于解析,验证,操作和格式化日期的JavaScript日期库。

名单还在继续。那里有很多真正有用的包,可供所有人使用(对于我在这里省略的那些没有冒犯)。

应该使用Node.js的示例

CHAT

聊天是最典型的实时多用户应用程序。从IRC(在当天),通过在非标准端口上运行的许多专有和开放协议,到今天在Node.js中实现一切的能力,其中websockets在标准端口80上运行。

聊天应用程序实际上是Node.js的最佳示例:它是一个轻量级,高流量,数据密集型(但低处理/计算)的应用程序,可跨分布式设备运行。它也是一个很好的学习用例,因为它很简单,但它涵盖了你在典型的Node.js应用程序中使用的大部分范例。

让我们试着描绘它是如何工作的。

在最简单的例子中,我们在我们的网站上有一个聊天室,人们可以通过一对多(实际上所有)方式交换消息。例如,假设网站上有三个人都连接到我们的留言板。

在服务器端,我们有一个简单的Express.js应用程序,它实现了两件事:

一个GET /请求处理程序,它为包含消息板和“发送”按钮的网页提供服务,以初始化新的消息输入,以及

一个websockets服务器,用于侦听websocket客户端发出的新消息。

在客户端,我们有一个HTML页面,其中设置了几个处理程序,一个用于“发送”按钮单击事件,它接收输入消息并将其发送到websocket,另一个用于侦听新的传入消息在websockets客户端上(即,由服务器现在希望客户端显示的其他用户发送的消息)。

当其中一个客户发布消息时,会发生以下情况:

浏览器通过JavaScript处理程序捕获“发送”按钮,从输入字段(即消息文本)中获取值,并使用连接到我们服务器的websocket客户端(在网页初始化时初始化)发出websocket消息。

websocket连接的服务器端组件接收消息,并使用广播方法将其转发到所有其他连接的客户端。

所有客户端都通过在网页中运行的websockets客户端组件将新消息作为推送消息接收。然后,他们通过将新消息附加到电路板来获取消息内容并就地更新网页。

这是最简单的例子。对于更强大的解决方案,您可以使用基于Redis存储的简单缓存。或者在更高级的解决方案中,消息队列用于处理到客户端的消息路由以及更强大的传递机制,其可以覆盖临时连接丢失或在注册客户端脱机时存储消息。但无论您做出哪些改进,Node.js仍将按照相同的基本原则运行:对事件做出反应,处理许多并发连接,并保持用户体验的流畅性。

对象数据库顶部的API

虽然Node.js真的很适合实时应用程序,但它非常适合从对象DB(例如MongoDB)公开数据。JSON存储的数据允许Node.js在没有阻抗不匹配和数据转换的情况下运行。

例如,如果您正在使用Rails,那么您将从JSON转换为二进制模型,然后在Backbone.js,Angular.js等使用数据时将它们作为JSON通过HTTP公开,甚至是简单的jQuery AJAX调用。使用Node.js,您可以使用REST API公开您的JSON对象,供客户端使用。此外,在从数据库读取或写入时(如果您使用的是MongoDB),您无需担心在JSON和其他任何内容之间进行转换。总之,通过在客户端,服务器和数据库中使用统一的数据序列化格式,可以避免需要多次转换。

排队输入

如果您收到大量并发数据,您的数据库可能会成为瓶颈。如上所述,Node.js可以轻松地自己处理并发连接。但是因为数据库访问是一种阻塞操作(在这种情况下),我们遇到了麻烦。解决方案是在数据真正写入数据库之前确认客户端的行为。

通过这种方法,系统可以在高负载下保持其响应性,这在客户端不需要确认成功数据写入时尤其有用。典型的例子包括:记录或写入用户跟踪数据,分批处理,直到以后才使用; 以及不需要立即反映的操作(例如更新Facebook上的“喜欢”计数),其中最终的一致性(在NoSQL世界中经常使用)是可以接受的。

数据通过某种缓存或消息排队基础结构(如RabbitMQ或ZeroMQ)排队,并通过单独的数据库批处理写入过程或计算密集型处理后端服务进行消化,这些服务是在更好的平台中编写的,用于执行此类任务。类似的行为可以用其他语言/框架实现,但不能在相同的硬件上实现,具有相同的高维护吞吐量。

简而言之:使用Node,您可以将数据库写入到一边并稍后处理它们,就像它们成功一样。

数据流

在更传统的Web平台中,HTTP请求和响应被视为孤立事件; 事实上,他们实际上是溪流。可以在Node.js中使用此观察来构建一些很酷的功能。例如,可以在文件仍在上传时处理文件,因为数据通过流进入,我们可以以在线方式处理它。这可以用于实时音频或视频编码,以及不同数据源之间的代理(参见下一节)。

代理

Node.js很容易用作服务器端代理,它可以以非阻塞方式处理大量的同时连接。它对于使用不同响应时间代理不同服务或从多个源点收集数据特别有用。

例如:考虑服务器端应用程序与第三方资源进行通信,从不同来源提取数据,或将图像和视频等资产存储到第三方云服务。

尽管存在专用代理服务器,但如果您的代理基础架构不存在或者您需要本地开发解决方案,则使用Node可能会有所帮助。通过这个,我的意思是你可以构建一个客户端应用程序与Node.js开发服务器的资产和代理/存根API请求,而在生产中你可以处理这种与专用代理服务(nginx,HAProxy等)的交互)。

BROKERAGE - 股票交易者的仪表板

让我们回到应用程序级别。桌面软件占主导地位,但可以很容易地用实时网络解决方案取代的另一个例子是经纪人的交易软件,用于跟踪股票价格,执行计算/技术分析,以及创建图表/图表。

切换到基于Web的实时解决方案将允许经纪人轻松切换工作站或工作场所。很快,我们可能会开始在佛罗里达州的海滩上看到它们......或者伊维萨岛或巴厘岛。

应用监控仪表板

另一个常见的用例,其中Node-with-web-socket完全适合:跟踪网站访问者并实时可视化他们的交互。

您可以从用户那里收集实时统计信息,甚至可以通过在访问渠道中的特定点打开通信渠道时与访问者进行有针对性的互动,将其移至更高级别。(如果你有兴趣,这个想法已经被CANDDi产品化了。)

想象一下,如果您能够实时了解访问者的行为,那么如何改善您的业务 - 如果您能够想象他们的互动。使用Node.js的实时双向套接字,现在就可以了。

系统监控仪表板

现在,让我们访问基础设施方面的事情。例如,想象一下,SaaS提供商希望为其用户提供服务监控页面,如GitHub的状态页面。通过Node.js事件循环,我们可以创建一个功能强大的基于Web的仪表板,以异步方式检查服务的状态,并使用websockets将数据推送到客户端。

内部(公司内部)和公共服务的状态都可以使用该技术实时和实时报告。进一步推动这一想法并尝试设想电信运营商,云/网络/托管提供商或某些金融机构中的网络运营中心(NOC)监控应用程序,所有这些应用程序都运行在由Node.js和websockets支持的开放Web堆栈上而不是Java和/或Java Applet。

注意:不要尝试在Node中构建硬实时系统(即需要一致响应时间的系统)。Erlang可能是该类应用程序的更好选择。

可以使用Node.js的位置

服务器端Web应用程序

带有Express.js的Node.js也可用于在服务器端创建经典Web应用程序。但是,虽然可能,Node.js将携带呈现HTML的请求 - 响应范例不是最典型的用例。有人支持和反对这种方法。以下是一些需要考虑的事实:

优点:

如果您的应用程序没有任何CPU密集型计算,那么您可以使用Javascript存储对象数据库(如MongoDB)从上到下构建它,甚至可以在数据库级别构建它。这显着简化了发展(包括招聘)。

Crawlers收到一个完全呈现的HTML响应,这比单个页面应用程序或在Node.js上运行的websockets应用程序更具SEO。

缺点:

任何CPU密集型计算都会阻止Node.js的响应,因此线程平台是一种更好的方法。或者,您可以尝试扩展计算[*]。

将Node.js与关系数据库一起使用仍然非常痛苦(更多细节见下文)。如果您正在尝试执行关系操作,请帮自己一个忙,并选择Rails,Django或ASP.Net MVC等任何其他环境。

[*]这些CPU密集型计算的替代方案是创建一个高度可扩展的MQ支持环境,该环境具有后端处理功能,以使Node成为一个面向前端的“职员”,以异步方式处理客户端请求。

不应该使用Node.js的地方

服务器端WEB应用程序W / A关系数据库的背后

例如,将Node.js与Express.js与Ruby on Rails进行比较时,在访问PostgreSQL,MySQL和Microsoft SQL Server等关系数据库时,曾经有过一个干净的决策支持后者。

Node.js的关系数据库工具仍处于早期阶段。另一方面,Rails自动提供开箱即用的数据访问设置以及数据库架构迁移支持工具和其他Gems(双关语)。Rails及其对等框架具有成熟且经过验证的Active Record或Data Mapper数据访问层实现。[*]

但事情发生了变化。SequelizeTypeORMBookshelf在成为成熟的ORM解决方案方面走了很长的路。如果您希望从GraphQL查询生成SQL,那么可能还需要查看Join Monster

[*]使用Node作为前端,同时保持Rails后端并轻松访问关系数据库是可能的,而且并不罕见。

相关: 后端:使用Gatsby.js和Node.js进行静态站点更新

重型服务器端计算/处理

当涉及到繁重的计算时,Node.js并不是最好的平台。不,你绝对不想在Node.js中构建一个Fibonacci计算服务器。通常,任何CPU密集型操作都会消除Node提供的所有吞吐量优势及其事件驱动的非阻塞I / O模型,因为任何传入的请求都会在线程被数字运算占用时被阻止 - 假设您正在尝试在您响应请求的同一个Node实例中运行计算。

如前所述,Node.js是单线程的,只使用一个CPU核心。在多核服务器上添加并发性时,Node核心团队正在以集群模块的形式完成一些工作[ref:http://nodejs.org/api/cluster.html]。您还可以通过nginx反向代理后面很容易地运行几个Node.js服务器实例。

使用群集,您仍然应该将所有繁重的计算卸载到在更合适的环境中编写的后台进程,并让它们通过像RabbitMQ这样的消息队列服务器进行通信。

即使您的后台处理最初可能在同一服务器上运行,这种方法也有可能实现非常高的可伸缩性。这些后台处理服务可以轻松地分发到单独的工作服务器,而无需配置前置Web服务器的负载。

当然,您也可以在其他平台上使用相同的方法,但是使用Node.js,您可以获得我们所讨论的高reqs / sec吞吐量,因为每个请求都是一个非常快速有效的小任务。

结论

我们讨论了Node.js从理论到实践,从它的目标和抱负开始,并以其最佳点和陷阱结束。当人们遇到Node的问题时,它几乎总是归结为阻塞操作是所有邪恶的根源 --99%的Node滥用是直接后果。

在Node中,阻塞操作是所有邪恶的根源 - 99%的Node滥用是直接后果。

请记住:从未创建过Node.js来解决计算扩展问题。它的创建是为了解决I / O扩展问题,它确实很好

为什么要使用Node.js?如果您的用例不包含CPU密集型操作,也不访问任何阻塞资源,您可以利用Node.js的优势,享受快速,可扩展的网络应用程序。欢迎来到实时网站。

专注全栈大前端,爱前端整理了一批2019年最新WEB前端教学视频,不论是零基础想要学习前端还是学完在工作想要提升自己,这些资料都会给你带来帮助,从HTML到各种框架,帮助所有想要学好前端的同学,学习规划、学习路线、学习资料、问题解答。只要加入全栈大前端学习交流Q群:137503198,即可免费获取。