Node.js是什么?

506

我不太清楚 Node.js 到底是什么。可能是因为我主要是一名基于网络的企业应用程序开发人员。它是什么,有什么用处呢?

我目前的理解是:

  1. 编程模型是事件驱动的,特别是处理I/O的方式。
  2. 它使用JavaScript语言,解释器是V8
  3. 可以轻松创建并发服务器应用程序。

我的理解正确吗?如果是,那么事件驱动的 I/O 有什么好处,它只是用于并发处理吗?此外, Node.js 的方向是成为像 JavaScript 的框架(基于 V8 的编程模型)吗?

10个回答

617

我在工作中使用Node.js,发现它非常强大。如果被迫选择一个词来描述Node.js,我会说“有趣”(这不是一个完全积极的形容词)。社区充满活力,而且不断壮大。尽管JavaScript有些奇怪,但它是一种非常好的编程语言。同时,你每天都会重新思考自己对“最佳实践”和良好结构化代码模式的理解。现在有大量的想法涌入Node.js,而在其中工作会让你接触到所有这些思想——这是一种很好的脑力训练。

在生产环境中使用Node.js是完全可行的,但与文档中所承诺的“轻松部署”相去甚远。从Node.js v0.6.x开始,“cluster”已经集成到平台中,提供了一个必要的基础构件之一,但我的“production.js”脚本仍然需要大约150行的逻辑来处理创建日志目录、回收死亡工作进程等任务。对于一个“严肃”的生产服务,您还需要准备好限制传入连接并执行Apache对PHP的所有操作。公平地说,Ruby on Rails也有这个确切的问题。它通过两种互补的机制来解决:1)将Ruby on Rails / Node.js置于专用的Web服务器(用C编写并进行了反复测试),如Nginx(或Apache / Lighttd)后面。Web服务器可以有效地提供静态内容、访问日志、重写URL、终止SSL、强制访问规则和管理多个子服务。对于击中实际节点服务的请求,Web服务器通过代理请求。2)使用像Unicorn这样的框架来管理工作进程、定期回收它们等。我还没有找到一个看起来完全成熟的Node.js服务框架;它可能存在,但我还没有找到它,仍然使用我手动编写的大约150行的“production.js”。

阅读像Express这样的框架,似乎标准做法就是通过一个全能的Node.js服务来提供所有内容..."app.use(express.static(__dirname + '/public'))"。对于低负载的服务和开发来说,这可能还可以。但是一旦您尝试在您的服务上投入大量负载并让其运行24/7,您很快就会发现推动大型站点使用经过良好烘焙、硬化的C代码(如Nginx)作为站点前端并处理所有静态内容请求的动机(直到您设置了Amazon CloudFrontCDN)。有趣而毫不掩饰地消极看待此事,请参见this guy

Node.js也越来越多地被用于非服务方面。即使您使用其他工具来提供Web内容,您仍然可以使用Node.js作为构建工具,使用npm模块组织您的代码,使用Browserify将其缝合成单个资源,并使用uglify-js压缩它以进行部署。对于处理Web,JavaScript是一个完美的阻抗匹配,通常这使得它成为最容易攻击的路径。例如,如果您想浏览一堆JSON响应负载,您应该使用我的underscore-CLI模块,这是结构化数据的实用工具包。

优点/缺点:

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

与简单的每个请求一个进程模型(LAMP)相比:

  • 优点:可扩展到数千个活动连接。非常快且高效。对于一个 Web 集群,这可能意味着相比 PHP 或 Ruby,所需的盒子数量减少了 10 倍。
  • 优点:编写并行模式很容易。想象一下,你需要从 Memcached 中获取三个(或 N 个) blob。在 PHP 中执行此操作...你刚刚编写了获取第一个 blob、然后是第二个、第三个的代码?哇,那太慢了。有一个特殊的 PECL 模块可以解决 Memcached 的这个具体问题,但如果你想在数据库查询期间并行获取一些 Memcached 数据怎么办?在 Node.js 中,由于范例是异步的,在 Web 请求中同时执行多个任务非常自然。
  • 缺点:异步代码比同步代码基本上更复杂,对于没有牢固理解并发执行实际含义的开发人员来说,最初的学习曲线可能会很难。不过,它远不如编写带锁定的任何类型的多线程代码困难。
  • 缺点:如果计算密集型请求运行时间为 100 毫秒,则会阻塞处理在同一 Node.js 进程中正在处理的其他请求...也就是说,合作式多任务处理。这可以通过 Web Workers 模式来缓解(分离一个子进程来处理昂贵的任务)。或者,你可以使用大量的 Node.js 工作者,并且只让每个工作者同时处理单个请求(仍然相当高效,因为没有进程回收)。
  • 缺点:运行生产系统比 Apache + PHP、PerlRubyCGI 模型要复杂得多。未处理的异常将导致整个进程崩溃,需要逻辑来重新启动失败的工作者(请参见 cluster)。具有错误本机代码的模块可能会使进程硬崩溃。每当工作者死亡时,它正在处理的任何请求都将被丢弃,因此一个有错误的 API 可能会轻易地降低其他共同托管的 API 的服务质量。

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

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

如果想要从另一个角度了解JavaScript和Node.js,可以查看从Java到Node.js这篇博客文章,其中介绍了一位Java开发者学习Node.js的印象和经验。


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

帮助程序 / JavaScript糖:

  • Underscore.js - 使用它。就这样做。它可以使您的代码变得漂亮且易读,例如 _.isString() 和 _.isArray()。否则,我不确定您如何编写安全的代码。此外,为了增强命令行功夫,请查看我的 Underscore-CLI

异步模式模块:

  • Step - 一种非常优雅的方式来表达串行和并行动作的组合。我个人推荐。请查看我的帖子,了解Step代码的样子。
  • Futures - 更加灵活(这真的是好事吗?)的通过需求表达顺序的方式。可以表达诸如“同时启动a、b、c。当A和B完成时,启动AB。当A和C完成时,启动AC。”这种灵活性需要更多的注意,以避免工作流中的错误(例如从未调用回调或多次调用回调)。请参见Raynos的帖子,了解使用futures的方法(这篇文章让我“懂得”了futures)。
  • Async - 传统的库,每个模式都有一个方法。在我的宗教转变为step之前,我就开始使用它,并且后来意识到Async中的所有模式都可以用单一更易读的范例在Step中表达。
  • TameJS - 由OKCupid编写,它是一个预编译器,添加了一个新的语言原语“await”,用于优雅地编写串行和并行工作流。这个模式看起来很棒,但它需要预编译。我对这个还没有下定决心。
  • StreamlineJS - TameJS的竞争对手。我倾向于Tame,但你可以自己做决定。

或者阅读与作者的这个面板访谈,了解有关异步库的所有内容。

Web 框架:

  • Express 优秀的 Ruby on Rails 式框架,用于组织网站。它使用 JADE 作为 XML/HTML 模板引擎,使得构建 HTML 变得不那么痛苦,甚至变得优雅。
  • jQuery 虽然技术上不是一个 Node 模块,但是 jQuery 迅速成为客户端用户界面的事实标准。jQuery 提供类似 CSS 的选择器来“查询”一组 DOM 元素,然后可以对其进行操作(设置处理程序、属性、样式等)。在同样的方向上,Twitter 的 Bootstrap CSS 框架,Backbone.js 用于 MVC 模式,以及 Browserify.js 用于将所有 JavaScript 文件拼合成单个文件。这些模块正在成为事实标准,因此如果您没有听说过它们,至少应该查看一下。

测试:

  • JSHint - 必须使用; 我起初没有使用它,现在看来是无法理解的。JSLint添加了许多类似于Java这样的编译语言的基本验证。不匹配的括号,未声明的变量,各种形状和大小的错误。你还可以打开各种我称之为“分析模式”的形式,其中你可以验证空格等样式,如果这是你的菜,那就没问题--但真正的价值在于获得即时反馈,指出你忘记关闭“)”的确切行数...而无需运行代码并击中有问题的行。"JSHint"是Douglas CrockfordJSLint更可配置的变体。
  • Mocha竞争对手Vows,我开始更喜欢它。这两个框架都处理基本的东西足够好,但是复杂模式往往更容易在Mocha中表达。
  • Vows非常优雅。并且它会打印出一个可爱的报告(--spec),显示哪些测试用例通过/失败了。花30分钟学习它,你就可以轻松地为你的模块创建基本测试。
  • Zombie - 使用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中,一个新的连接只是一个非常小的堆分配。在某些平台上,启动新进程需要更多的内存,可能要1MB。但真正的代价是上下文切换所带来的开销。当你有10^6个内核线程时,内核必须做很多工作才能弄清楚谁应该下一个执行。已经做了很多工作来构建Linux的O(1)调度程序,但最终,拥有单个事件驱动进程比10^6个进程竞争CPU时间要更有效率得多。此外,在过载条件下,多进程模型的表现非常糟糕,会饿死关键的管理服务,特别是SSHD(这意味着您甚至无法登录到机器上查看问题)。
      Node.js是单线程且无锁的。作为一种非常谨慎的设计选择,每个进程只有一个线程。因此,多个线程同时访问数据在根本上是不可能的。因此,不需要锁。线程很难,真的很难。如果你不相信这一点,那就意味着你还没有做过足够多的线程编程。正确使用锁是困难的,并会导致非常难以追踪的错误。消除锁和多线程使得最棘手的一类bug消失了。这可能是Node.js最大的优势。
      但我如何利用我的16核机器呢?
      有两种方法:
      1.对于像图像编码这样的大型重计算任务,Node.js可以启动子进程或向其他工作进程发送消息。在这种设计中,您将有一个线程管理事件流和N个处理重计算任务并占用其他15个CPU的进程。
      2.为了扩展webservice的吞吐量,应该在一个盒子上运行多个Node.js服务器,每个核心一个,使用cluster(在Node.js v0.6.x中,官方的"cluster"模块取代了具有不同API的learnboost版本)。这些本地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引擎(所有现代引擎都在后台执行大量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"变量不必是只读的。这个强大的语言特性使得异步编程更加简洁和 less painful.
      编写异步代码总是比编写简单的单线程脚本更加复杂,但是通过Node.js,它并不那么困难,并且除了效率和可扩展性能够处理成千上万的并发连接之外,你还可以获得许多其他好处...

1
@Nick - 这是错误的。"并发问题"被缓解了,因为Node是单线程的。在Node中,锁定根本不存在;它在单线程范式中是不需要的。 - Dave Dopson
1
附带说明:我实际上编辑了足够多次,以至于这篇文章变成了“社区维基”(阈值为10次编辑)。我错误地认为这是某种荣誉,而实际上它只会阻止通过赞同获得声望。最终,一个在社区维基状态之前的投票者点击了“取消投票”(希望是出于偶然的原因 :)),我失去了声望...混乱中,我提交了http://meta.stackexchange.com/questions/129941/bug-with-reputation-calculation-for-downvote-on-highly-rated-answers-200,并被告知了“社区维基”的真正含义。版主们很好心地移除了社区维基状态。 :) - Dave Dopson
1
@John - 我的调试注释同样适用于普通的异步操作。为了进行调试,我只需要在某个函数调用中添加 "process.nextTick (...)" 语句。然后当它抛出异常时,我的堆栈跟踪将以 process.nextTick 开头,这对我并不是很有帮助。我真正想知道的是:“是哪个堆栈调度了 process.nextTick?” 我称该数据为 "因果链",它让我想起 Java 异常处理中的 'causedBy' ... 低层代码抛出异常,中层代码捕获了 LL 异常并抛出 FrameworkMethodFailedException - 如果没有 'causedBy',则来自 LL 代码的堆栈将会丢失。 - Dave Dopson
@jmacinnes - Node没有任何锁定代码,因此也没有锁定错误。通常,Java服务将使用多个线程,因此至少需要一定级别的锁定。确实,可以编写基于事件循环的Java服务,并具有与Node类似的权衡,但通常不会这样做。 - Dave Dopson
JS 没有标准库,也许社区应该创建一个? - MetaGuru
显示剩余8条评论

213

我认为它的优点有:

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

  2. 能够在单个进程上处理数千个并发连接,并且开销很小。

  3. JavaScript非常适合事件循环,具有头等函数对象和闭包。人们已经知道如何在浏览器中使用它来响应用户启动的事件。

  4. 很多人都懂JavaScript,即使不是程序员也可能懂。可以说它是最受欢迎的编程语言之一。

  5. Web服务器和浏览器上都使用JavaScript可以减少两个编程环境之间的阻力不匹配问题,数据结构可以通过JSON进行交流,而这些数据结构在方程两侧都能够工作。重复的表单验证代码可以在服务器和客户端之间共享。


1
@postfuturist:它在许多替代方案中表现得非常出色。在许多情况下,它也轻松击败了Java 6。不错! - Adam Crossland
1
@postfuturist 我认为你是在与Java 6 -Xint进行比较。试着与Java 6 -server进行比较。 - fedesilva
@iJK yammer.com 是一个使用 node.js 的工作应用程序。 - Gerard Banasig
1
有趣的是,10年前我在ASP中编写JScript,这样我就可以(a)避免VBScript的糟糕体验,(b)在客户端和服务器上使用相同的语言,以及(c)重用我自己和其他人的JS库来处理字符串等等。 - Antony Quinn
@AntonyQuinn 好有趣,我不知道还有其他人在ASP中使用JScript,尽管那里的缺点是处理COM枚举很麻烦。除此之外,它运行良好。 - Tracker1
4
为什么你只编辑了这篇帖子中的“传统废话”?我认为如果你一开始就写了这个,212人不会投票支持这篇帖子。 - Julien Fouilhé

85

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 is genuinely exciting,这是我对该库/平台的介绍...我觉得它相当不错。


4
如何在不使用锁、线程、进程和闭包的情况下实现事件驱动IO?我有一种感觉,这些概念与函数式编程和Erlang非常相似。 - Jeff
1
据我所知,它是作为一个简单的事件循环实现的。V8已经具备了回调等功能,就像任何JavaScript实现一样。 - rfunduk
2
Node.js的IO事件循环意味着在任何给定时间点最多只有一件事情正在进行。我看到两个重要的收益:没有线程切换的开销,因此node.js非常快,其次,许多Java臭名昭著的典型并发错误是不可能发生的。 - nalply
1
JavaScript支持闭包,在node.js中它们一直被广泛使用(如此匿名函数在这里的例子中)。如何在不使用闭包的情况下实现事件驱动的IO? - panzi
@panzi:没有注意到Jeffrey在他列出的node.js实现“不包括”的东西中包括闭包。显然,JavaScript中的每个函数都是其作用域周围的闭包 :) - rfunduk
此外,Node IO 模型非常类似于 Erlang 的设计点,只是没有 Erlang 的花哨的消息概念。 - Dave Dopson

35

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

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

它因其性能和执行并行操作的能力而受欢迎。

理解node.js是我目前为止找到的最好的node.js解释。

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


13
闭包是在创建它的上下文中执行代码的一种方式。
对于并发来说,这意味着您可以定义变量,然后启动一个非阻塞的I/O函数,并向其发送匿名函数以进行回调。
当任务完成时,回调函数将在具有变量的上下文中执行,这就是闭包。
闭包之所以非常适合编写具有非阻塞I/O的应用程序,是因为很容易管理异步执行函数的上下文。

8
两个很好的例子是关于如何管理模板并使用渐进增强。您只需要一些轻量级的JavaScript代码,就可以完美地使其工作。
我强烈建议您观看和阅读这些文章:
- 视频 Glass Node - Node.js YUI DOM 操作 选择任何一种语言,试着记住您如何管理HTML文件模板以及您需要做什么才能更新CSS类名在您的DOM结构中(例如,用户单击菜单项,您希望将其标记为“已选”并更新页面内容)。
使用Node.js与在客户端JavaScript代码中实现一样简单。获取您的DOM节点并将CSS类应用于该节点。获取您的DOM节点并innerHTML内容(您需要一些额外的JavaScript代码来执行此操作。阅读文章以了解更多信息)。
另一个很好的例子是,您可以使用同一段代码使网页兼容打开或关闭JavaScript。假设您有一个使用JavaScript创建的日期选择器,允许用户使用日历选择任何日期。您可以编写(或使用)同一段JavaScript代码,使其在打开或关闭JavaScript时都能正常工作。

7
以下是您需要翻译的内容:

有一个非常好的快餐店类比能够最好地解释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浏览器。


6

好的,我知道

  • Node的目标是提供一种简单的方式来构建可伸缩的网络程序。
  • Node在设计上与像Ruby的Event Machine或Python的Twisted等系统类似且受其影响。
  • 为V8 JavaScript提供事件驱动I/O。

对我来说,这意味着你的三个假设都是正确的。这个库看起来非常有前途!


1
很多时候我发现关于页面相当模糊。 - Jeff

6
此外,不要忘记提到谷歌的V8引擎非常快。它实际上将JavaScript代码转换为机器码,并具有编译二进制代码相匹配的性能。因此,除了其他所有优点之外,它的速度非常快。

3

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

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

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

是的

问题:它可以轻松用于创建并发服务器应用程序。

是的,虽然您需要手动编写大量JavaScript。最好查看一个框架,例如http://www.easynodejs.com/-它附带完整的在线文档和示例应用程序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接