什么是Node.js?

我没有完全得到Node.js的全部内容。 也许这是因为我主要是一个基于Web的业务应用程序开发人员。 它是什么,它有什么用途?

我迄今为止的理解是:

  1. 编程模型是事件驱动的,尤其是它处理I / O的方式 。
  2. 它使用JavaScript ,解析器是V8 。
  3. 它可以很容易地用来创建并发的服务器应用程序。

我的理解是否正确? 如果是的话,那么这个并发的I / O有什么好处呢? 另外,Node.js的方向是成为像基于JavaScript(基于V8的)编程模型的框架吗?

我认为其优点是:

  1. 在一个非常快的虚拟机(V8)上以动态语言(JavaScript)进行Web开发。 它比Ruby,Python或Perl快得多。

  2. 能够在单个进程上以最小的开销处理数千个并发连接。

  3. JavaScript是完美的事件循环与一流的功能对象和闭包。 人们已经知道如何在浏览器中使用它来响应用户发起的事件。

  4. 很多人已经知道JavaScript,即使是自称不是程序员的人也是如此。 它可以说是最流行的编程语言。

  5. 在Web服务器上使用JavaScript以及浏览器可以减少两种编程环境之间的阻抗不匹配,这两种编程环境之间可以通过JSON进行数据结构的通信,这两种编程环境在等式两边都是一样的。 重复的表单验证代码可以在服务器和客户端之间共享

我在工作中使用Node.js,并发现它非常强大。 被迫选择一个词来描述Node.js,我会说“有趣的”(这不是一个纯粹的积极的形容词)。 这个社区充满活力,并在不断发展。 尽管JavaScript有其独特之处,但却可以成为一门伟大的代码语言。而且,您每天都会重新思考自己对“最佳实践”的理解以及结构良好的代码模式。 现在有大量的想法流入Node.js,并且在其中工作,让您感受到这种想法 – 伟大的心理举重。

生产中的Node.js是绝对有可能的,但是远不是文档所承诺的“交钥匙”部署。 使用Node.js v0.6.x,“集群”已经集成到平台中,提供了一个基本的构建块,但是我的“production.js”脚本仍然有150行逻辑来处理创建日志目录,回收死亡工作人员等。对于“严重”的生产服务,您还需要做好准备,遏制传入的连接,并完成Apache为PHP所做的所有工作。 公平地说, Ruby on Rails有这个确切的问题。 它是通过两个互补的机制解决的:1)把Ruby放在Rails / Node.js后面,像Nginx (或者Apache / Lighttd )一样,放在一个专用的web服务器(用C语言编写,并且测试到底)。 Web服务器可以有效地提供静态内容,访问日志记录,重写URL,终止SSL ,强制访问规则以及管理多个子服务。 对于碰到实际节点服务的请求,Web服务器通过代理请求。 2)使用像独角兽这样的框架来管理工作进程,定期回收它们等等。我还没有找到一个似乎完全被烘焙的Node.js服务框架; 它可能存在,但我还没有找到它,仍然在我的手卷“production.js”中使用150行。

像Express这样的阅读框架使得看起来像标准的做法是通过一个全能的Node.js服务来服务所有的事情…“app.use(express.static(__ dirname +'/ public'))” 。 对于低负载的服务和开发,这可能是好的。 但是,当您尝试将大量时间加载到您的服务上并使其全天候运行时,您将很快发现推动大型网站获得良好烘焙,强化的C代码(如Nginx面向其网站并处理所有这些问题的动机)的静态内容请求(…直到您设置CDN ,如Amazon CloudFront ))。 对于这个有点幽默和毫不掩饰的负面看法,看看这个人 。

Node.js也在寻找越来越多的非服务用途。 即使你正在使用别的东西来提供web内容,你仍然可以使用Node.js作为构建工具,使用npm模块来组织你的代码,使用Browserify将其绑定到一个资源中,然后使用uglify-js来缩小它的部署范围。 对于网络来说,JavaScript是一个完美的阻抗匹配,并且经常使它成为最简单的攻击路线。 例如,如果您想通过一堆JSON响应有效负载进行打包,则应使用我的下划线 – CLI模块(结构化数据的实用工具带)。

优点缺点:

  • Pro:对于一个服务器人来说,在后端编写JavaScript已经成为学习现代UI模式的“门户药物”。 我不再畏惧编写客户端代码。
  • Pro:倾向于鼓励适当的错误检查(实际上所有的回调函数都返回错误,唠叨程序员来处理它;而且async.js和其他库处理“失败,如果任何这些子任务失败”的范例比典型的同步代码好得多)
  • Pro:一些有趣且通常很难的任务变得微不足道 – 比如获取正在运行的任务的状态,工作者之间的通信或共享缓存状态
  • Pro:庞大的社区和庞大的图书馆基于稳定的包管理器(npm)
  • Con:JavaScript没有标准库。 当你使用JSON.parse或其他一些不需要添加npm模块的构建方法的时候,你会习惯于导入这样的功能。 这意味着有五个版本的一切。 即使包含在Node.js“核心”中的模块,如果您对默认实现不满意,也可能有五个变体。 这导致了快速的演变,但也有一定程度的混乱。

与一个简单的一次处理每个请求模型( LAMP )相比:

  • Pro:可扩展到数千个活动连接。 非常快,非常有效。 对于一个网站来说,这可能意味着所需的箱子数量比PHP或Ruby减少10倍
  • 亲:写平行模式很容易。 想象一下,你需要从Memcached中获取三个(或N个)blob。 在PHP中执行此操作…是否只是将代码写入第一个blob,然后是第二个,然后是第三个? 哇,这很慢。 有一个特殊的PECL模块可以解决Memcached的特定问题,但是如果您想要与数据库查询并行地提取一些Memcached数据呢? 在Node.js中,因为范例是异步的,所以有一个web请求并行执行多个事情是非常自然的。
  • Con:异步代码比同步代码更复杂,如果开发人员没有充分了解并行执行的实际意义,那么对于开发人员而言,前期学习曲线就很难了。 尽管如此,与使用锁定编写任何类型的多线程代码相比,它要困难得多。
  • Con:如果一个计算密集型的请求运行,例如100ms,它将会停止处理在同一个Node.js进程中正在处理的其他请求… AKA, 协同多任务 。 这可以通过Web Workers模式(分离子流程来处理昂贵的任务)来缓解。 或者,您可以使用大量的Node.js工作者,并且只让每个人同时处理一个请求(因为没有进程回收,所以仍然相当高效)。
  • Con:运行一个生产系统要比Apache + PHP, Perl , Ruby等CGI模型复杂得多。未处理的异常将会导致整个过程的失败,因此需要逻辑来重新启动失败的工作者(参见集群 )。 具有错误本地代码的模块可能会导致进程崩溃。 每当工作人员死亡,其处理的任何请求都将被丢弃,因此一个漏洞百出的API可能轻易地降低其他协同处理的API的服务。

与Java / C#/ C编写“真正的”服务(真的吗?)

  • Pro:在Node.js中执行异步操作比在任何其他地方执行线程安全操作都容易,并且可以提供更大的好处。 Node.js是迄今为止我曾经工作过的最不痛苦的异步范例。使用好的库,它比编写同步代码稍微难一些。
  • 专业:没有多线程/锁定的错误。 诚然,您可以在撰写更详细的代码时进行投入,这些代码可以表达正确的异步工作流程,而不会阻止操作。 而且你需要编写一些测试并使其正常工作(这是一种脚本语言,胖指法变量名只能在单元测试时间捕获)。 但是,一旦你开始工作, 海森堡的表面面积 – 奇怪的问题,只有一百万次运行 – 表面面积要低得多。 编写Node.js代码的税很大程度上被加载到编码阶段。 那么你往往会得到稳定的代码。
  • Pro:JavaScript对于表达功能来说更加轻量。 用文字来证明这一点很难,但是JSON ,动态类型,lambda表示法,原型继承,轻量级模块,无论如何…它只是用较少的代码来表达相同的想法。
  • Con:也许你真的很喜欢Java中的编码服务?

有关JavaScript和Node.js的另一个角度,请查看从Java到Node.js ,这是一篇关于Java开发人员的博客文章,介绍如何学习Node.js。


模块在考虑节点时,请记住,您选择的JavaScript库将定义您的体验。 大多数人至少使用两个异步模式助手(Step,Futures,Async)和一个JavaScript糖模块( Underscore.js )。

助手/ JavaScript糖:

  • Underscore.js – 使用这个。 去做就对了。 它使你的代码更好,可读性好,比如_.isString()和_.isArray()。 我真的不知道你怎么能写安全的代码,否则。 另外,为了增强命令行功能,请查看我自己的Underscore-CLI 。

异步模式模块:

  • 步骤 – 表达串行和并行操作组合的非常优雅的方式。 我个人的建议。 请参阅我的帖子 ,了解步骤代码的外观。
  • 期货 – 更灵活(真的是一件好事?)通过需求表达订单的方式。 可以并行表示“a,b,c”,当A和B完成时,启动AB,当A和C完成时,启动AC。 这种灵活性需要更多的关注,以避免工作流程中的错误(如从不调用回调或多次调用)。 请参阅Raynos关于使用期货的文章 ( 这是让我“获得”期货的文章)。
  • 异步 – 更传统的库,每种模式都有一种方法。 在开始我的宗教转换之前,我开始了这一步,后来认识到Async中的所有模式都可以用一个更具可读性的范式来表达。
  • TameJS – 由OKCupid编写的,它是一个预编译器,它增加了一种新的语言“等待”,以优雅地编写串行和并行工作流程。 模式看起来很神奇,但确实需要预编译。 我仍然决定这个。
  • StreamlineJS – 与TameJS的竞争对手。 我倾向于驯服,但你可以自己决定。

或者阅读关于异步库的所有信息,请参阅本小组对作者的访谈 。

Web框架:

  • Express Ruby on Rails-esk框架来组织网站。 它使用JADE作为XML / HTML模板引擎,这使得构建HTML远不那么痛苦,甚至几乎优雅。
  • jQuery虽然技术上不是节点模块,但jQuery很快成为客户端用户界面的事实标准。 jQuery提供了类似于CSS的选择器来查询DOM元素,然后可以对其进行操作(设置处理程序,属性,样式等)。 同样,Twitter的Bootstrap CSS框架, MVC模式的Backbone.js ,以及Browserify.js将所有JavaScript文件拼接成单个文件。 这些模块已经成为事实上的标准,所以如果你还没有听说过它们,至少应该检查一下。

测试:

  • JSHint – 必须使用; 起初我没有使用这个,现在看起来不可理解。 JSLint增加了一些用Java编译语言获得的基本验证。 不匹配的括号,未声明的变量,许多形状和大小的类型。 你也可以打开我称之为“肛门模式”的各种形式,在那里你可以验证空白的风格和什么,这是好的,如果这是你的一杯茶 – 但真正的价值来自获得即时反馈的确切行号你忘了关闭“)”…而不必运行你的代码,并击中犯规线。 “JSHint”是Douglas Crockford的JSLint的一个更可配置的变体。
  • 摩卡竞争对手誓言,我开始喜欢。 这两个框架都能很好地处理基础知识,但是在Mocha中复杂的模式往往更容易表达。
  • 誓言誓言真的很高雅。 并打印出一个可爱的报告(–spec),显示哪些测试用例通过/失败。 花30分钟时间学习一下,你可以用最小的努力为你的模块创建基本的测试。
  • 僵尸 – 使用JSDom作为虚拟“浏览器”的HTML和JavaScript无头测试。 非常强大的东西。 将它与Replay结合起来,可以快速确定浏览器内代码的测试结果。
  • 评论如何“思考”测试:
    • 测试是非可选的。 使用JavaScript这样的动态语言,几乎没有静态检查。 例如,将两个参数传递给期望为4的方法在代码执行之前不会中断。 非常低的酒吧在JavaScript中创建错误。 基本测试对弥补编译语言的验证差距至关重要。
    • 忘记验证,只是让你的代码执行。 对于每种方法,我的第一个验证案例是“没有任何中断”,最常见的情况就是这种情况。 证明你的代码运行时不会丢失80%的错误,并且会做很多事情来提高你的代码的可信度,以至于你会发现自己回头去添加你跳过的细微的验证案例。
    • 从小处开始,打破惯性障碍。 我们都懒惰,时间紧迫,很容易把测试看成是“额外的工作”。 所以从小开始 写测试用例0 – 加载你的模块并报告成功。 如果你强迫自己做这么多,那么测试的惯性障碍就会​​被打破。 这是<30分钟,这是你第一次做,包括阅读文件。 现在编写测试用例1 – 调用你的一个方法,并验证“没有中断”,也就是说,你不会再犯错。 测试案例1应该花费不到一分钟的时间。 随着惯性的消失,增加测试覆盖范围变得很容易。
    • 现在用你的代码演化你的测试。 不要被模拟服务器和所有这些“正确的”端到端测试所吓倒。 代码从简单开始,发展到处理新的情况; 测试也应该。 当您为代码添加新的案例和新的复杂性时,请添加测试用例以运行新的代码。 当您发现错误时,请添加验证和/或新的案例来覆盖有缺陷的代码。 当你正在调试和失去一段代码的信心,回去并添加测试,以证明它正在做你认为它是。 捕获示例数据的字符串(来自您所调用的其他服务,您所搜索的网站),并将它们提供给您的解析代码。 这里有几个例子,在那里改进了验证,最后你会得到高度可靠的代码。

另外,请查看推荐的Node.js模块的官方列表 。 但是, GitHub的 Node Modules Wiki更完整,也是一个很好的资源。


为了理解Node,考虑一些关键的设计选择是有帮助的:

Node.js是基于事件异步 / 非阻塞的 。 事件,就像一个传入的HTTP连接将会触发一个JavaScript函数,它会执行一些工作,并启动其他异步任务,如连接到数据库或从另一个服务器提取内容。 一旦这些任务被启动,事件函数完成,Node.js返回到睡眠状态。 只要发生其他事情,比如建立数据库连接或者外部服务器响应内容,回调函数就会触发,并执行更多的JavaScript代码,甚至可能启动更多异步任务(如数据库查询)。 通过这种方式,Node.js将高兴地交叉多个并行工作流的活动,在任何时间点运行任何未被阻止的活动。 这就是为什么Node.js在管理数千个同时连接方面做得如此出色的原因。

为什么不像其他人那样每个连接使用一个进程/线程呢? 在Node.js中,新的连接只是一个非常小的堆分配。 旋转一个新的进程需要更多的内存,一些平台上的兆字节。 但是真正的成本是与上下文切换相关的开销。 当你有10 ^ 6的内核线程时,内核必须做很多工作来确定下一步应该执行什么。 一大堆工作已经为Linux构建了一个O(1)调度器,但是最终,只有一个事件驱动的进程比10 ^ 6进程竞争CPU时间更有效率。 而且,在超负荷的情况下,多进程模型的表现非常糟糕,导致关键的管理和管理服务,特别是SSHD(意味着你甚至不能登录盒子来弄清楚它是如何搞砸的)。

Node.js是单线程锁定免费的 。 Node.js作为一个非常慎重的设计选择,每个进程只有一个线程。 正因为如此,多线程同时访问数据基本上是不可能的。 因此,不需要锁。 线程很难。 真的很难。 如果你不相信,你没有做足够的线程编程。 正确锁定是非常困难的,并且会导致很难追踪的错误。 消除锁和多线程使得最糟糕的一类错误消失。 这可能是节点的最大优势。

但是我如何利用我的16核心盒呢?

两种方式:

  1. 对于图像编码等繁重的计算任务,Node.js可以启动子进程或将消息发送到其他工作进程。 在这个设计中,你将有一个线程来管理事件流和N个进程,执行繁重的计算任务,并咀嚼其他15个CPU。
  2. 为了在web服务上扩展吞吐量,您应该在一个盒子上运行多个Node.js服务器,每个核心使用一个集群 (使用Node.js v0.6.x,此处链接的官方“集群”模块将取代learnboost版本一个不同的API)。 然后,这些本地的Node.js服务器可以在一个套接字上竞争,接受新的连接,平衡它们之间的负载。 一旦连接被接受,它就被绑定到这些共享进程中的一个。 从理论上讲,这听起来很糟糕,但是在实践中它运行得很好,可以避免编写线程安全代码的麻烦。 另外,这意味着Node.js可以获得出色的CPU高速缓存亲和性,更有效地利用内存带宽。

Node.js可以让你做一些非常强大的事情,而不会冒汗。 假设你有一个Node.js程序,它执行各种任务,在TCP端口上侦听命令,编码一些图像,无论如何。 通过五行代码,您可以添加一个基于HTTP的Web管理门户,显示活动任务的当前状态。 这很容易做到:

var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(myJavascriptObject.getSomeStatusInfo()); }).listen(1337, "127.0.0.1"); 

现在你可以打一个URL并检查你正在运行的进程的状态。 添加几个按钮,你有一个“管理门户”。 如果你有一个正在运行的Perl / Python / Ruby脚本,那么“投入一个管理门户”并不是那么简单。

但不是JavaScript慢/坏/邪恶/魔鬼产生? JavaScript有一些奇怪的地方,但是“好的部分”有一个非常强大的语言,在任何情况下,JavaScript都是客户端(浏览器)上的语言。 JavaScript在这里停留; 其他语言则将其定位为IL,世界级的人才正在竞相制作最先进的JavaScript引擎。 由于JavaScript在浏览器中的作用,正在引发大量的工程工作,以使JavaScript快速发展。 V8是最新的和最伟大的JavaScript引擎,至少在本月。 它在效率和稳定性方面吹走了其他脚本语言(看着你,Ruby)。 在微软,谷歌和Mozilla等大型团队中,竞争建立最好的JavaScript引擎(它不再是一个JavaScript的“解释器”,因为所有的现代引擎都会在JIT下编译大量的JIT与解释只作为执行一次代码后备)。 是的,我们都希望能够修复一些JavaScript语言的选择,但实际上并不是那么糟糕。 而且这种语言非常灵活,你真的不是编写JavaScript代码,而是编写Step或者jQuery,而不是JavaScript,所以这些库定义了经验。 要构建Web应用程序,您几乎必须了解JavaScript,所以在服务器上进行编码具有某种技能集合的协同作用。 这使我不害怕编写客户端代码。

另外,如果你真的讨厌JavaScript,你可以使用像CoffeeScript这样的语法糖。 或其他创建JavaScript代码的其他内容,例如Google Web Toolkit (GWT)。

说到JavaScript,什么是“关闭”? – 非常漂亮地说,你保留在呼叫链上的词汇范围变量。 ;) 喜欢这个:

 var myData = "foo"; database.connect( 'user:pass', function myCallback( result ) { database.query("SELECT * from Foo where id = " + myData); } ); // Note that doSomethingElse() executes _BEFORE_ "database.query" which is inside a callback doSomethingElse(); 

看看你怎样才能使用“myData”而不做任何尴尬的事情,像把它存入一个对象? 与Java不同,“myData”变量不必是只读的。 这种强大的语言功能使得异步编程更加冗长而且不那么痛苦。

编写异步代码总是要比编写简单的单线程脚本更复杂,但是使用Node.js并不难,除了数千个并发连接的效率和可伸缩性之外,还有很多好处。 ..

V8是JavaScript的一个实现。 它可以让你运行独立的JavaScript应用程序(等等)。

Node.js只是一个为V8编写的库,它可以实现I / O。 这个概念有点棘手的解释,我敢肯定有人会回答比我更好的解释… …的要点是,而不是做一些输入或输出,等待它发生,你只是不要等待为它完成。 例如,请求文件的上次编辑时间:

 // Pseudo code stat( 'somefile' ) 

这可能需要几毫秒,或者可能需要几秒钟。 使用事件I / O,您只需发出请求,而不是等待您附加请求结束时执行的回调。

 // Pseudo code stat( 'somefile', function( result ) { // Use the result here } ); // ...more code here 

这使得它非常类似于浏览器中的JavaScript代码(例如,具有Ajax风格的功能)。

有关更多信息,你应该看看这篇文章Node.js是真正令人兴奋的 ,这是我的图书馆/平台的介绍…我发现它相当不错。

Node.js是为服务器端JavaScript代码构建的开源命令行工具。 你可以下载一个tarball ,编译并安装源码。 它可以让你运行JavaScript程序。

JavaScript是由Chrome浏览器中使用的Google开发的JavaScript引擎V8执行的。 它使用JavaScript API来访问网络和文件系统。

它的性能和执行并行操作的能力是受欢迎的。

了解node.js是迄今为止我发现的node.js的最好解释。

以下是关于这个话题的一些很好的文章。

  • 学习带有Node.js的服务器端JavaScript
  • 这一次,你将学习Node.js

闭包是在创建它的上下文中执行代码的一种方式。

这意味着您可以定义变量,然后启动非阻塞I / O函数,并为其回调发送一个匿名函数。

当任务完成时,回调函数将在变量的上下文中执行,这是闭包。

对于使用非阻塞I / O编写应用程序来说,关闭原因非常好,因为管理非异步执行的函数的上下文非常简单。

关于如何管理模板并使用渐进式增强功能,有两个很好的例子。 你只需要几个轻量级的JavaScript代码就可以完美的工作。

我强烈建议你观看和阅读这些文章:

  • 视频玻璃节点
  • Node.js YUI DOM操作

拿起任何语言,并尝试记住你将如何管理你的HTML文件模板,你必须做什么来更新你的DOM结构中的单个CSS类名称(例如,用户点击菜单项,你想要标记为“选择”并更新页面的内容)。

使用Node.js就像在客户端JavaScript代码中一样简单。 获取您的DOM节点,并将其应用于您的CSS类。 获取您的DOM节点和innerHTML您的内容(您将需要一些额外的JavaScript代码来做到这一点,阅读文章了解更多)。

另一个很好的例子就是,您可以使用同一段代码打开或关闭JavaScript,使您的网页兼容。 想象一下,你有一个JavaScript的日期选择,可以让你的用户使用日历来选择任何日期。 您可以编写(或使用)相同的JavaScript代码片段,以使JavaScript在打开或关闭状态下工作。

有一个非常好的快餐场所比喻,最好的解释了Node.js的事件驱动模型,请参阅完整的文章, Node.js,医生办公室和快餐店 – 了解事件驱动的编程

这里是一个总结:

如果快餐联盟采用传统的基于线程的模式,那么您可以点菜,排队等候,直到您收到。 在你的订单完成之前,你身后的人将无法订购。 在事件驱动的模式中,您可以订购食物,然后离线等待。 其他人都可以自由订购。

Node.js是事件驱动的,但大多数Web服务器都是基于线程的.York解释了Node.js是如何工作的:

  • 您可以使用Web浏览器在Node.js Web服务器上请求“/about.html”。

  • Node.js服务器接受你的请求并调用一个函数从磁盘检索这个文件。

  • 当Node.js服务器正在等待要检索的文件时,它将服务下一个Web请求。

  • 检索文件时,会在Node.js服务器队列中插入一个回调函数。

  • Node.js服务器执行这个函数,在这种情况下,它将呈现“/about.html”页面并将其发送回您的Web浏览器。

那么, 我明白这一点

  • Node的目标是提供一种构建可扩展网络程序的简单方法。
  • Node在设计上与Ruby的Event Machine或Python的Twisted系统相似,并且受其影响。
  • V8 JavaScript的Evented I / O。

对我来说,这意味着你在三个假设中都是正确的。 图书馆肯定看起来很有希望

此外,不要忘记提及谷歌的V8是非常快的。 它实际上是将JavaScript代码转换为与编译二进制文件相匹配的性能的机器代码。 所以,除了所有其他伟大的事情,它是快速的。

问:编程模型是事件驱动的,尤其是它处理I / O的方式 。

正确。 它使用回调函数,所以任何访问文件系统的请求都会导致请求被发送到文件系统,然后Node.js将开始处理下一个请求。 只有在I / O请求从文件系统获得响应时,才会担心I / O请求,届时它将运行回调代码。 但是,可能会发出同步I / O请求(即阻塞请求)。 开发人员可以选择异步(回调)还是同步(等待)。

问:它使用JavaScript,解析器是V8。

问:它可以很容易地用来创建并发的服务器应用程序。

是的,尽管您需要手动编写相当多的JavaScript代码。 最好看看一个框架,比如http://www.easynodejs.com/ – 它带有完整的在线文档和示例应用程序。

Interesting Posts