什么是Node.js?

我不完全明白node . js是什么意思。也许是因为我主要是一个基于web的商业应用程序开发人员。它是什么?它有什么用?

目前我的理解是:

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

我的理解正确吗?如果是,那么事件I/O的好处是什么,它只是更多的并发性的东西吗?另外,Node.js的方向是成为一个框架,像基于JavaScript(基于V8)的编程模型吗?

482088 次浏览

嗯,我理解

  • Node的目标是提供一个简单的方法
  • Node在设计上类似于Ruby的Event Machine或Python的Twisted等系统,并受其影响。
  • V8 javascript的事件I/O。

对我来说,这意味着你的三个假设都是正确的。图书馆看起来确实很有前途!

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是真正令人兴奋的 .js,这是我对库/平台的介绍…我觉得很不错。

我认为优点是:

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

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

  3. JavaScript非常适合用于带有第一类函数对象和闭包的事件循环。人们已经知道如何以这种方式使用它,在浏览器中使用它来响应用户发起的事件。

  4. 很多人已经了解JavaScript,甚至包括那些自称不是程序员的人。它可以说是最流行的编程语言。

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

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

对于并发来说,这意味着你可以定义变量,然后初始化一个非阻塞的I / O函数,并为它的回调函数发送一个匿名函数。

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

闭包非常适合使用非阻塞I/O编写应用程序的原因是,它非常容易管理异步执行的函数的上下文。

node . js是一个为服务器端JavaScript代码构建的开源命令行工具。你可以下载一个压缩文件,编译并安装源代码。它允许你运行JavaScript程序。

JavaScript由V8执行,它是谷歌开发的JavaScript引擎,用于浏览器。它使用JavaScript API访问网络和文件系统。

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

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

下面是一些关于这个主题的好文章。

两个很好的例子是关于如何管理模板和如何使用渐进式增强。您只需要几段轻量级的JavaScript代码就可以使它完美地工作。

我强烈建议你看一下这些文章:

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

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

另一个很好的例子是,你可以让你的网页兼容JavaScript打开或关闭同一段代码。假设您有一个用JavaScript编写的日期选择,允许用户使用日历选择任何日期。您可以编写(或使用)同一段JavaScript代码,使其在打开或关闭JavaScript时正常工作。

我在工作中使用Node.js,发现它非常强大。如果非要用一个词来描述Node.js,我会说“有趣”(这不是一个纯粹的积极形容词)。社区充满活力,不断增长。JavaScript尽管有一些奇怪之处,但却是一种很好的编程语言。并且您每天都会重新思考自己对“最佳实践”和结构良好的代码模式的理解。现在有一股巨大的思想能量流入Node.js,在其中工作可以让你接触到所有这些思想——这是一次伟大的精神举重。

Node.js在生产环境中是绝对可行的,但与文档中承诺的“交钥匙”部署相去甚远。使用Node.js v0.6。X,“集群”已经集成到平台中,提供了一个基本的构建块,但我的“production.js”脚本仍然有大约150行逻辑来处理诸如创建日志目录,回收死去的工人等事情。对于一个“严肃的”生产服务,你还需要准备好限制传入的连接,并完成Apache为PHP所做的所有事情。公平地说,Ruby on Rails有这个确切的问题。它通过两个互补的机制来解决:1)把Ruby on Rails/Node.js放在一个专用的web服务器后面(用C编写并测试),比如Nginx(或Apache / Lighttd)。web服务器可以有效地提供静态内容、访问日志、重写url、终止SSL、执行访问规则和管理多个子服务。对于击中实际节点服务的请求,web服务器通过代理发送请求。2)使用像独角兽这样的框架来管理工作进程,定期回收它们,等等。我还没有找到一个看起来完全成熟的Node.js服务框架;它可能存在,但我还没有找到它,仍然在我的手卷“production.js”中使用~150行。

阅读像表达这样的框架,似乎标准的实践是通过一个多面手的Node.js服务来提供所有服务……“app.use(表达。Static (__dirname + '/public'))”。对于低负载的服务和开发,这可能没问题。但是,一旦你试图在你的服务上投入大量的时间负载并让它全天候运行,你很快就会发现促使大型网站使用精心制作的、加固的c代码(如Nginx)作为站点的前端并处理所有静态内容请求的动机(…直到你建立一个CDN,比如Amazon CloudFront))。关于这一点有点幽默和毫不掩饰的负面看法,请参阅这家伙

Node.js也发现了越来越多的非服务用途。即使你正在使用其他东西来提供web内容,你仍然可以使用Node.js作为构建工具,使用npm模块来组织你的代码,Browserify将其缝合到单个资产中,uglify-js将其缩小以进行部署。对于处理web, JavaScript是一个完美的阻抗匹配,这通常使它成为最简单的攻击路线。例如,如果你想通过一堆JSON响应负载,你应该使用我的underscore-CLI模块,结构化数据的实用带。

利与弊:

  • 正方观点:对于一个从事服务器工作的人来说,在后台编写JavaScript是学习现代UI模式的“入门药物”。我不再害怕编写客户端代码。
  • 利:倾向于鼓励适当的错误检查(err几乎由所有回调返回,唠叨程序员处理它;此外,与典型的同步代码相比,async.js和其他库处理“如果这些子任务中的任何一个子任务失败就会失败”的范例要好得多。
  • 正面观点:一些有趣且通常困难的任务变得微不足道——比如获取正在运行的任务的状态,在工作人员之间通信,或共享缓存状态
  • 优点:巨大的社区和大量基于可靠的包管理器(npm)的优秀库
  • 缺点:JavaScript没有标准库。您已经习惯了导入功能,以至于在使用JSON时感觉很奇怪。解析或其他不需要添加NPM模块的内置方法。这意味着每样东西都有五个版本。即使是Node.js“核心”中包含的模块,如果你对默认实现不满意,也有5个变体。这导致了快速的进化,但也带来了某种程度的混乱。

相对于一个简单的每个请求一个进程的模型():

  • 优点:可扩展到数千个活动连接。非常快,非常高效。对于web团队来说,这可能意味着与PHP或Ruby相比所需的盒子数量减少了10倍
  • 利:编写并行模式很容易。假设你需要从Memcached中获取三个(或N) blobs。在PHP中做这个…你刚刚写的代码是取第一个,然后是第二个,然后是第三个?哇,真慢。有一个特殊的PECL模块来修复Memcached的特定问题,但是如果你想在数据库查询的同时获取一些Memcached数据呢?在Node.js中,因为范式是异步的,让一个web请求并行地做多件事是非常自然的。
  • 缺点:异步代码从根本上来说比同步代码更复杂,如果不充分理解并发执行的实际含义,开发人员就很难预先学习。不过,这比编写任何一种带锁的多线程代码要容易得多。
  • 缺点:如果一个计算密集型请求运行,例如,100 ms,它将暂停正在同一Node.js进程中处理的其他请求的处理…即,cooperative-multitasking。这可以通过Web Workers模式缓解(分离出一个子流程来处理昂贵的任务)。或者,你可以使用大量的Node.js worker,并且只让每个worker并发处理一个请求(仍然相当高效,因为没有进程循环)。
  • 缺点:运行一个生产系统要比Apache + PHP、PerlRubyCGI模型复杂得多。未处理的异常将使整个进程崩溃,需要重新启动失败的worker(参见cluster)。带有错误原生代码的模块可能会导致进程硬崩溃。每当一个worker死亡,它所处理的任何请求都将被丢弃,因此一个有bug的API可以很容易地降低其他联合托管API的服务。

相对于用Java / c# / C (C?真的吗?)

  • 优点:在Node.js中实现异步要比在其他任何地方实现线程安全更容易,而且可以提供更大的好处。Node.js是迄今为止我使用过的最轻松的异步范例。使用好的库,只比编写同步代码稍微难一点。
  • 优点:没有多线程/锁定错误。的确,您需要预先编写更详细的代码,以表达没有阻塞操作的适当异步工作流。并且您需要编写一些测试并使其工作(它是一种脚本语言,并且只在单元测试时捕获变量名的错误指法)。但是,一旦你让它工作,heisenbugs的表面积——一百万次运行中只出现一次的奇怪问题——表面积就会低得多。编写Node.js代码的任务在编码阶段被大量地提前加载。这样你就会得到稳定的代码。
  • 优点:JavaScript在表达功能方面更加轻量级。很难用语言来证明这一点,但是JSON,动态类型,lambda符号,原型继承,轻量级模块,等等……它只是倾向于用更少的代码来表达相同的思想。
  • 缺点:也许你真的非常非常喜欢用Java编写服务代码?

要从另一个角度了解JavaScript和Node.js,请查看From Java to Node.js .js,这是一篇关于Java开发人员学习Node.js的印象和经验的博客文章。


< >强模块 在考虑node时,请记住你选择的JavaScript库将定义你的体验。大多数人至少使用两个,异步模式帮助器(Step, Futures, Async)和JavaScript糖模块(Underscore.js)

Helper / JavaScript

  • Underscore.js -使用这个。尽管去做。它使您的代码漂亮和可读的东西像_.isString(),和_.isArray()。我不知道你怎么能写出安全的代码。此外,对于增强的command-line-fu,请查看我自己的Underscore-CLI

异步模式模块:

  • 一步 -一个非常优雅的方式来表达组合的串行和并行操作。这是我个人的建议。关于Step代码的样子,请参阅我的帖子
  • 期货 -更灵活的(这真的是一件好事吗?)通过需求来表达顺序的方式。可以表达像“并行启动a, b, c”这样的东西。当A和B结束时,开始AB。当A和C结束时,开始AC。”这样的灵活性需要更多的注意来避免工作流中的错误(比如从不调用回调,或者多次调用它)。参见Raynos的文章关于使用期货(这是让我“获得”期货的帖子)。
  • 异步 -更传统的库,每个模式有一个方法。在我虔诚地皈依step和后来意识到Async中的所有模式都可以用一个更易于阅读的范例在step中表达之前,我就开始了这一点。
  • TameJS -由OKCupid编写,它是一个预编译器,添加了一个新的语言原语“await”,用于优雅地编写串行和并行工作流。这个模式看起来很棒,但它确实需要预编译。这件事我还没决定。
  • StreamlineJS - TameJS的竞争对手。我倾向于泰姆,但你可以自己做决定。

或者要阅读所有关于异步库的内容,请参阅作者的这个小组面试

Web框架:

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

测试:

  • JSHint -必须使用;我一开始没有使用这个,现在看来难以理解。JSLint添加了一些基本的验证,您可以使用Java之类的编译语言进行验证。不匹配的括号,未声明的变量,多种形状和大小的类型。你也可以打开我称之为“肛门模式”的各种形式,在那里你可以验证空白和诸如此类的风格,这是可以的,如果这是你的那杯茶-但真正的价值来自于得到准确的行号上的即时反馈,你忘记了一个关闭”)... 而不必运行代码并点击违规行。"JSHint"是道格拉斯CrockfordJSLint的一个更可配置的变体。
  • 摩卡的竞争对手誓言,我开始喜欢。这两个框架都能很好地处理基础问题,但是复杂的模式在Mocha中更容易表达。
  • 誓言誓言真的很优雅。它会打印出一个可爱的报告(——spec),显示哪些测试用例通过/失败。只需花30分钟学习它,您就可以为您的模块创建基本的测试。
  • 僵尸 -使用JSDom作为虚拟“浏览器”对HTML和JavaScript进行无头测试。非常强大的东西。将它与重播结合起来,可以快速地对浏览器内代码进行确定性测试。
  • 关于如何“思考”测试的评论:
    • 测试是不可选的。对于像JavaScript这样的动态语言,非常很少有静态检查。例如,将两个参数传递给一个期望为4的方法,直到代码执行时才会中断。在JavaScript中产生错误的门槛很低。基本测试对于弥补编译语言的验证差距至关重要。
    • 忘记验证,只执行代码。对于每个方法,我的第一个验证用例是“没有损坏”,这是最常触发的情况。证明你的代码能够正常运行而不抛出80%的错误,这将极大地提高你对代码的信心,你会发现自己会回头添加你跳过的细微的验证用例。
    • 从小处着手,打破惯性障碍。我们都很懒惰,时间紧迫,很容易将测试视为“额外的工作”。所以从小事做起。编写测试用例0 -加载模块并报告成功。如果你强迫自己做这么多,那么测试的惯性障碍就被打破了。第一次需要30分钟,包括阅读文档。现在编写测试用例1——调用您的一个方法并验证“没有中断”,也就是说,您没有得到错误返回。测试用例1应该用不到一分钟。随着惯性的消失,逐渐扩展您的测试覆盖范围变得很容易。
    • 现在用代码改进测试。不要被使用模拟服务器的“正确的”端到端测试所吓倒。代码一开始很简单,然后发展到处理新的情况;测试也应该如此。当您向代码中添加新的用例和新的复杂性时,请添加测试用例来执行新代码。当您发现错误时,添加验证和/或新案例来覆盖有缺陷的代码。当您正在调试并对一段代码失去信心时,请返回并添加测试以证明它正在执行您认为的操作。捕获示例数据字符串(来自您调用的其他服务、您抓取的网站等等),并将它们提供给解析代码。这里有一些情况,那里有改进的验证,最终您将得到高度可靠的代码。
    • 李< / ul > < / >

    另外,查看推荐的Node.js模块的官方名单。然而,GitHub的 节点模块更完整,是一个很好的资源。


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

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

    为什么不像其他人一样每个连接使用一个进程/线程?< / em >在Node.js中,一个新的连接只是一个非常小的堆分配。启动一个新进程需要更多的内存,在某些平台上需要1兆字节。但真正的成本是与上下文切换相关的开销。当你有10^6个内核线程时,内核必须做很多工作来确定接下来应该执行谁。为Linux构建O(1)调度器已经做了很多工作,但最终,单个事件驱动进程比10^6个进程竞争CPU时间要有效得多。此外,在过载条件下,多进程模型的行为非常糟糕,无法提供关键的管理和管理服务,特别是SSHD(这意味着您甚至无法登录到该机器以了解它到底有多糟糕)。

    Node.js是单线程的锁自由。Node.js作为一个非常慎重的设计选择,每个进程只有一个线程。因此,多个线程同时访问数据基本上是不可能的。因此,不需要任何锁。线程是硬的。真的很难。如果您不相信这一点,那么您还没有做足够多的线程编程。获得正确的锁定是很困难的,并且会导致很难追踪的错误。消除锁和多线程使最讨厌的一类bug消失了。这可能是node最大的优势。

    但是我如何利用我的16核盒子?< / em >

    两种方式:

    1. 对于像图像编码这样的大型繁重的计算任务,Node.js可以启动子进程或向其他工作进程发送消息。在这种设计中,有一个线程管理事件流,N个进程执行繁重的计算任务,并占用其他15个cpu。
    2. 为了在web服务上扩展吞吐量,你应该在一个机器上运行多个Node.js服务器,每个核心一个,使用集群 (With Node.js v0.6. js)。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不是很慢/不好/邪恶/恶魔的产物吗?< / em > JavaScript有一些奇怪的地方,但有“好的部分”有一个非常强大的语言,在任何情况下,JavaScript是客户端(浏览器)上的语言。JavaScript将继续存在;其他语言将其作为一种IL,世界一流的人才正在竞相开发最先进的JavaScript引擎。由于JavaScript在浏览器中的角色,大量的工程工作被投入到使JavaScript快速运行。V8是最新最好的javascript引擎,至少在这个月是这样。它在效率和稳定性方面都超过了其他脚本语言(看看你,Ruby)。随着微软、谷歌和Mozilla的庞大团队致力于这个问题,它只会变得更好,竞争构建最好的JavaScript引擎(它不再是JavaScript“解释器”,因为所有现代引擎都在底层进行大量JIT编译,解释只是作为执行一次代码的后备)。是的,我们都希望能够修复一些比较奇怪的JavaScript语言选择,但它真的没有那么糟糕。这门语言非常灵活,你实际上不是在编写JavaScript,而是在编写Step或jQuery——在JavaScript中,库定义了体验。要构建web应用程序,无论如何你都必须了解JavaScript,所以在服务器上使用它进行编码有一种技能组合的协同作用。它使我不再害怕编写客户端代码。

    此外,如果你真的讨厌JavaScript,你可以使用像CoffeeScript这样的语法糖。或者其他任何创建JavaScript代码的东西,比如Google  Web 工具包 (GWT)。

    说到JavaScript,什么是“闭包”?< / em >——这是一种很花哨的说法,表示你在调用链上保留了词法范围内的变量。,)是这样的:

    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代码转换为机器代码,具有与已编译二进制代码相匹配的性能。所以,连同所有其他伟大的东西,它是疯狂的快。

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

以下是摘要:

如果快餐店遵循传统的基于线程的模式,你会点你的食物,排队直到你收到它。在你点完餐之前,你后面的人不能点餐。在事件驱动模型中,你点了食物,然后离开队伍等待。其他人就可以自由点餐了。

Node.js是事件驱动的,但大多数web服务器是基于线程的。York解释了Node.js的工作原理:

  • 您使用web浏览器在a上请求“/about.html”

  • .js web服务器
  • Node.js服务器接受你的请求并调用一个函数来检索

  • 当Node.js服务器正在等待文件被检索时,它将被删除

  • .服务下一个web请求
  • 当文件被检索时,有一个回调函数为

  • .
  • Node.js服务器执行该函数 呈现“/about.html”页面并将其发送回web浏览器。李" < / p > < / >

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

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

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

是的

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

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