首页 文章

什么是Node.js? [关闭]

提问于
浏览
506

我不完全了解Node.js的全部内容 . 也许是因为我主要是一个基于Web的业务应用程序开发人员 . 它是什么以及它的用途是什么?

到目前为止,我的理解是:

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

  • 它使用JavaScript,解析器是V8 .

  • 它可以很容易地用于创建并发服务器应用程序 .

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

10 回答

  • 619

    我认为其优点是:

    • 在VM上以动态语言(JavaScript)进行Web开发,速度非常快(V8) . 它比Ruby,Python或Perl快得多 .

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

    • JavaScript非常适合具有第一类函数对象和闭包的事件循环 . 人们已经知道如何使用它在浏览器中使用它来响应用户发起的事件 .

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

    • 在Web服务器和浏览器上使用JavaScript可以减少两个编程环境之间的阻抗不匹配,这两个编程环境可以通过JSON传递数据结构,这两个方程在方程式的两侧都是相同的 . 可以在服务器和客户端等之间共享重复的表单验证代码 .

  • 213

    我在工作中使用Node.js,并发现它非常强大 . 被迫选择一个词来描述Node.js,我会说“有趣”(这不是一个纯正的形容词) . 社区充满活力,不断发展壮大 . 尽管JavaScript很奇怪,但它可以成为一种很好的编码语言 . 而且你每天都会重新思考自己对“最佳实践”和结构良好的代码模式的理解 . 现在有很多想法流入Node.js,并且在其中工作会让你接触到所有这些思想 - 精神上的举重 .

    生产环境 中的Node.js绝对是可能的,但远远不是文档似乎承诺的"turn-key"部署 . 使用Node.js v0.6.x,"cluster"已经集成到平台中,提供了一个必不可少的构建块,但我的"production.js"脚本仍然是〜150行逻辑来处理诸如创建日志目录,回收死亡工作者之类的东西,对于"serious" 生产环境 服务,您还需要准备好限制传入连接并完成Apache为PHP所做的所有事情 . 公平地说,Ruby on Rails有这个确切的问题 . 它通过两种互补的机制解决:1)将Ruby放在Rails / Node.js后面的专用网络服务器(用C语言编写并测试到地狱和后面),如Nginx(或Apache / Lighttd) . Web服务器可以有效地提供静态内容,访问日志记录,重写URL,终止SSL,强制执行访问规则以及管理多个子服务 . 对于命中实际节点服务的请求,Web服务器代理请求 . 2)使用像Unicorn这样的框架来管理工作进程,定期回收它们等等 . 我发现它仍然在我的手工卷"production.js"中使用~150行 .

    Express这样的阅读框架使得看起来标准的做法就是通过一个万事通的Node.js服务来提供所有服务...... "app.use(express.static(__dirname + '/public'))" . 对于负载较低的服务和开发,'s probably fine. But as soon as you try to put big time load on your service and have it run 24/7, you'll很快就会发现推动大型网站拥有良好烘焙,强化的C代码(例如Nginx)面向其网站并处理所有静态内容请求的动机(......直到您设置了CDN,如Amazon CloudFront)) . 对于一个有点幽默和毫不掩饰的负面看法,请参阅this guy .

    Node.js也发现越来越多的非服务用途 . 即使您使用其他东西来提供Web内容,您仍可以使用Node.js作为构建工具,使用npm模块来组织代码,Browserify将其拼接成单个资源,然后使用uglify-js将其缩小以进行部署 . 对于处理Web,JavaScript是一个完美的impedance match,并且经常使它成为最简单的攻击途径 . 例如,如果你想浏览一堆JSON响应有效负载,你应该使用我的underscore-CLI模块,即结构化数据的实用带 .

    优点/缺点:

    • 专业版:对于服务器人来说,在后端编写JavaScript是学习现代UI模式的一种方法 . 我不再害怕编写客户端代码 .

    • Pro:倾向于鼓励正确的错误检查(几乎所有的回调都会返回错误,唠叨程序员来处理它;同样,async.js和其他库比典型的同步代码更好地处理"fail if any of these subtasks fails"范例)

    • 专业:一些有趣且通常很难的任务变得微不足道 - 比如获取飞行中的任务状态,工作人员之间的通信或共享缓存状态

    • 专业:基于坚实的包管理器(npm)的庞大社区和大量优秀的图书馆

    • Con:JavaScript没有标准库 . 当你使用JSON.parse或其他一些不需要添加npm模块的方法时,你已经习惯了导入功能,感觉很奇怪 . 这意味着一切都有五个版本 . 如果您对默认实现不满意,甚至包含在Node.js _732602中的模块还有五个变体 . 这导致快速进化,但也有一定程度的混乱 .

    与简单的每进程一个进程模型(LAMP):

    • Pro:可扩展到数千个活动连接 . 非常快速且非常高效 . 对于网络车队来说,这意味着与PHP或Ruby相比,所需的箱数减少了10倍

    • Pro:编写并行模式很容易 . 想象一下,你需要从Memcached中获取三个(或N个)blob . 在PHP中执行此操作...您只是编写代码获取第一个blob,然后是第二个,然后是第三个?哇,'s slow. There'是一个特殊的PECL模块来修复Memcached的特定问题,但是如果你想要与数据库查询并行获取一些Memcached数据呢?在Node.js中,因为范例是异步的,所以具有Web请求并行执行多个操作是非常自然的 .

    • Con:异步代码基本上比同步代码更复杂,如果没有深入理解并发执行实际意味着什么,那么前期学习曲线对于开发人员来说可能很难 . 但是,与使用锁定编写任何类型的多线程代码相比,它要困难得多 .

    • Con:如果计算密集型请求运行时间为100毫秒,则会停止处理在同一个Node.js进程中处理的其他请求... AKA,cooperative-multitasking . 这可以通过Web Workers模式(关闭子流程来处理昂贵的任务)来缓解 . 或者,您可以使用大量Node.js工作程序,并且只让每个工作程序同时处理单个请求(仍然相当有效,因为没有进程回收) .

    • Con:运行 生产环境 系统比Apache PHP,PerlRubyCGI模型复杂得多 . 未处理的异常会导致整个过程失效,需要逻辑重启失败的工作者(参见cluster) . 具有错误本机代码的模块可能会使进程难以崩溃 . 每当一个工作者死亡时,它所处理的任何请求都会被删除,因此一个错误的API很容易降低其他共同API的服务质量 .

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

    • Pro:在Node.js中执行异步比在其他任何地方执行线程安全更容易,并且可以提供更大的好处 . Node.js是迄今为止我曾经工作过的最不痛苦的异步范例 . 使用好的库,它只比编写同步代码稍微困难一些 .

    • Pro:没有多线程/锁定错误 . 没错,您可以在编写更详细的代码时进行投资,这些代码表达了一个没有阻塞操作的正确的异步工作流 . 而且你需要编写一些测试并使其工作(它是一种脚本语言,并且胖指法变量名只能在单元测试时捕获) . 但是,一旦你开始工作,表面区域就会出现一个奇怪的问题 - 只有一百万次运行 - 表面区域要低得多 . 编写Node.js代码的税收大量加载到编码阶段 . 然后你倾向于最终得到稳定的代码 .

    • Pro:JavaScript表达功能要轻得多 . 很难用文字证明这一点,但是JSON,动态类型,lambda符号,原型继承,轻量级模块,无论如何......它只是用较少的代码来表达相同的想法 .

    • Con:也许你真的非常喜欢用Java编写服务?

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


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

    助手/ JavaScript糖:

    • Underscore.js - 用这个 . 去做就对了 . 它使用_.isString()和_.isArray()之类的东西使代码变得美观可读 . 我不确定如何编写安全代码 . 另外,对于增强的命令行fu,请查看我自己的Underscore-CLI .

    异步模式模块:

    • Step - 表达串行和并行动作组合的一种非常优雅的方式 . 我的个人推荐 . 有关步骤代码的信息,请参阅my post .

    • Futures - 更灵活(这真的是一件好事吗?)通过要求表达排序的方式 . 能够表达像_732621这样的事情 . 这种灵活性需要更多的注意,以避免工作流中的错误(如从不调用回调,或多次调用它) . 关于使用期货,请参阅Raynos's post(这是让我"get"期货的帖子) .

    • Async - 更传统的库,每种模式都有一种方法 . 我在开始宗教转换之前开始使用它,然后逐步认识到Async中的所有模式都可以用一个更易读的范例来表达 .

    • TameJS - 由OKCupid撰写,它仍然在这个问题上做出决定 .

    • StreamlineJS - TameJS的竞争对手 . 我倾向于驯服,但你可以自己决定 .

    或者阅读有关异步库的所有内容,请参阅作者的this panel-interview .

    Web框架:

    • Express用于组织网站的Great Ruby on Rails-esk框架 . 它使用JADE作为XML / HTML模板引擎,这使得构建HTML变得更加痛苦,甚至更加优雅 .

    • jQuery虽然技术上不是节点模块,但jQuery正迅速成为客户端用户界面的事实标准 . jQuery为'query'提供了类似CSS的选择器,用于可以对其进行操作的DOM元素集(设置处理程序,属性,样式等) . 同样,Twitter的Bootstrap CSS框架,Backbone.js用于MVC模式,Browserify.js将所有JavaScript文件拼接成单个文件 . 这些模块都成为事实上的标准,所以如果你没有听说过,你至少应该检查它们 .

    测试:

    • JSHint - 必须使用;我没有喝茶 - 但真正的 Value 来自于你忘记关闭的确切行号的即时反馈")" ...无需运行你的代码并点击违规行 . "JSHint"是Douglas CrockfordJSLint的更易配置的变体 .

    • Mocha誓言的竞争者,我开始更喜欢 . 两个框架都能很好地处理基础知识,但复杂的模式往往更容易在Mocha中表达 .

    • Vows誓言真的很优雅 . 它打印出一个可爱的报告(--spec),显示哪些测试用例通过/失败 . 花30分钟学习它,您可以轻松地为您的模块创建基本测试 .

    • Zombie - 使用JSDom作为虚拟"browser"对HTML和JavaScript进行无头测试 . 非常强大的东西 . 将它与Replay相结合,可以对浏览器内代码进行快速确定性测试 .

    • 关于如何"think about"测试的评论:

    • 测试是非可选的 . 使用像JavaScript这样的动态语言,很少有静态检查 . 例如,将两个参数传递给期望为4的方法,在执行代码之前不会中断 . 用于在JavaScript中创建错误的相当低的标准 . 基本测试对于弥补编译语言的验证差距至关重要 .

    • 忘记验证,只需让代码执行即可 . 对于每种方法,我的第一个验证案例是"nothing breaks",并且's the case that fires most often. Proving that your code runs without throwing catches 80% of the bugs and will do so much to improve your code confidence that you' ll会发现自己回过头来添加您跳过的细微差别验证案例 .

    • 从小处开始,打破惯性屏障 . 我们都很懒惰,时间紧迫,第一次这样做是<732656_ <30分钟,包括阅读文档 . 现在编写测试用例1 - 调用你的一个方法并验证"nothing breaks",也就是说,你没有收到错误 . 测试用例1应该不到一分钟 . 随着惯性消失,逐渐扩大测试覆盖范围变得容易 .

    • 现在使用您的代码改进您的测试 . 不要被使用模拟服务器和所有这些的"correct"端到端测试看起来感到害怕 . 代码开始简单,并逐步发展以处理新案例;测试也应该 . 在为代码添加新案例和新复杂性时,添加测试用例以执行新代码 . 当您发现错误时,请添加验证和/或新案例以涵盖有缺陷的代码 . 当您调试并对一段代码失去信心时,请返回并添加测试以证明它正在执行您认为的操作 . 捕获示例数据的字符串(来自您调用的其他服务,您搜索的网站,等等)并将它们提供给您的解析代码 . 这里有一些案例,改进了验证,最终你会得到高度可靠的代码 .

    另外,请查看推荐的Node.js模块的official list . 但是,GitHub's Node Modules Wiki要完整得多,资源也很好 .


    要了解Node,考虑一些关键设计选择会很有帮助:

    Node.js是 EVENT BASEDASYNCHRONOUS / NON-BLOCKING . 事件,如传入的HTTP连接,将触发一个JavaScript函数,该函数执行一些工作并启动其他异步任务,如连接到数据库或从另一个服务器提取内容 . 一旦启动这些任务,事件函数就会完成,Node.js会重新进入休眠状态 . 一旦发生其他事情,例如正在 Build 的数据库连接或外部服务器响应内容,回调函数触发,执行更多JavaScript代码,可能会启动更多异步任务(如数据库查询) . 通过这种方式,Node.js将愉快地交错多个并行工作流的活动,运行在任何时间点未被阻止的任何活动 . 这就是Node.js在管理数千个同时连接方面做得非常出色的原因 .

    Why not just use one process/thread per connection like everyone else? 在Node.js中,新连接只是一个非常小的堆分配 . 启动新进程需要更多内存,在某些平台上需要1兆字节 . 但实际成本是与上下文切换相关的开销 . 当你有10 ^ 6个内核线程时,内核必须做很多工作来确定下一步应该执行什么 . 一堆工作已经用于构建Linux的O(1)调度程序,但最终,它甚至可以登录框来弄清楚它是如何搞砸的 . )

    Node.js是 SINGLE THREADEDLOCK FREE . Node.js作为一个非常谨慎的设计选择,每个进程只有一个线程 . 正因为如此,它认为,你还没有做足够的线程编程 . 正确锁定很困难,导致很难找到的错误 . 消除锁和多线程使得最糟糕的一类错误消失 . 这可能是节点的最大优势 .

    But how do I take advantage of my 16 core box?

    两种方式:

    • 对于像图像编码这样的大型计算任务,Node.js可以启动子进程或向其他工作进程发送消息 . 在这个设计中,你有一个线程来管理事件流和N个进程执行繁重的计算任务并咀嚼其他15个CPU .

    • 为了在web服务上扩展吞吐量,你应该在一个盒子上运行多个Node.js服务器,每个核心一个,使用cluster(使用Node.js v0.6.x,这里链接的官方"cluster"模块取代了有一个的Learnboost版本不同的API) . 然后,这些本地Node.js服务器可以在套接字上竞争以接受新连接,从而 balancer 它们之间的负载 . 一旦接受连接,它就会紧密绑定到这些共享进程中的一个 . 从理论上讲,这听起来很糟糕,但在实践中它运行良好,可以避免编写线程安全代码的麻烦 . 此外,这意味着Node.js可以获得出色的CPU缓存关联性,更有效地利用内存带宽 .

    Node.js lets you do some really powerful things without breaking a sweat. 假设您有一个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脚本,那么“投入一个管理门户”并不是那么简单 .

    But isn't JavaScript slow / bad / evil / spawn-of-the-devil? JavaScript有一些奇怪的奇怪之处,但是由于"the good parts"在浏览器中有作用,因此大量的工程工作正在使JavaScript快速发展 . V8是最新最好的javascript引擎,至少在本月 . 它在效率和稳定性方面打破了其他脚本语言(看着你,Ruby) . 并且's only going to get better with huge teams working on the problem at Microsoft, Google, and Mozilla, competing to build the best JavaScript engine (It'不再是一个JavaScript "interpreter",因为所有现代引擎都会在引擎盖下进行大量编译,而解释仅仅是执行一次代码的回退 . 是的,我们都希望我们可以修复一些奇怪的JavaScript语言选择,但它编写JavaScript,你编写Step或jQuery - 比任何其他语言更多,在JavaScript中,库定义了体验 . 要构建Web应用程序,您无论如何都必须了解JavaScript,因此在服务器上使用它进行编码具有一种技能组合协同作用 . 这让我不怕写客户端代码 .

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

    Speaking of JavaScript, what's a "closure"? - 几乎可以说你在调用链中保留了词法范围的变量 . ;) 像这样:

    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,除了数千个并发连接的效率和可伸缩性之外,它并没有那么难以获得很多好处 . ..

  • 6

    V8是JavaScript的实现 . 它允许您运行独立的JavaScript应用程序(以及其他内容) .

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

    // Pseudo code
    stat( 'somefile' )
    

    这可能需要几毫秒,或者可能需要几秒钟 . 使用_832689_事件,您只需触发请求,而不是等待您附加一个在请求完成时运行的回调:

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

    这使它很像浏览器中的JavaScript代码(例如,具有Ajax样式功能) .

    有关更多信息,请查看文章Node.js is genuinely exciting,这是我对库/平台的介绍......我发现它非常好 .

  • 85

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

    JavaScript由V8执行,这是一个由Google开发的JavaScript引擎,用于Chrome浏览器 . 它使用JavaScript API来访问网络和文件系统 .

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

    了解node.js是我到目前为止找到的node.js的最佳解释 .

    以下是关于该主题的一些好文章 .

    使用Node.js学习服务器端JavaScript这次,您将学习Node.js

  • 35

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

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

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

    闭包非常适合编写具有非阻塞I / O的应用程序,因为管理异步执行的函数的上下文非常容易 .

  • 13

    两个很好的例子是关于如何管理模板并使用渐进增强功能 . 您只需要一些轻量级的JavaScript代码即可使其完美运行 .

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

    选择任何语言并尝试记住如何管理HTML文件模板以及如何更新DOM结构中的单个CSS类名称(例如,用户单击菜单项并且您希望将其标记为"selected"并更新页面内容) .

    使用Node.js就像在客户端JavaScript代码中一样简单 . 获取您的DOM节点并将CSS类应用于该节点 . 获取您的DOM节点和innerHTML您的内容(您将需要一些额外的JavaScript代码来执行此操作 . 阅读文章以了解更多信息) .

    另一个很好的例子是,您可以使用相同的代码打开或关闭JavaScript来使您的网页兼容 . 想象一下,您有一个用JavaScript制作的日期选择,允许您的用户使用日历获取任何日期 . 您可以编写(或使用)相同的JavaScript代码,以使其与您的JavaScript打开或关闭一起使用 .

  • 8

    有一个非常好的快餐店比喻,最能说明Node.js的事件驱动模型,请参阅完整文章,Node.js, Doctor’s Offices and Fast Food Restaurants – Understanding Event-driven Programming

    以下是摘要:

    如果快餐联合会遵循传统的基于线程的模式,那么您需要订购食物并排队等候直到收到食物 . 在您的订单完成之前,您身后的人将无法订购 . 在事件驱动的模型中,您订购食物然后离开等待 . 然后其他人都可以自由订购 .

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

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

    • Node.js服务器接受您的请求并调用函数从磁盘检索该文件 .

    • 当Node.js服务器正在等待检索文件时,它为下一个Web请求提供服务 .

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

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

  • 7

    好吧,I understand that

    Node的目标是提供一种简单的方法来构建可扩展的网络程序 . Node的设计类似于Ruby的Event Machine或Python的Twisted等系统 . 针对V8 javascript的求偶I / O.

    对我而言,这意味着你在所有三个假设中都是正确的 . 图书馆看起来很有前途!

  • 6

    此外,不要忘记提到谷歌的V8非常快 . 它实际上将JavaScript代码转换为具有编译二进制的匹配性能的机器代码 . 因此,除了所有其他伟大的东西,它是无助的快速 .

  • 3

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

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

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

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

    是的,虽然您需要手动编写相当多的JavaScript代码 . 查看一个框架可能会更好,例如http://www.easynodejs.com/ - 它带有完整的在线文档和示例应用程序 .

相关问题