什么是 Node.js?

发布于 2024-08-14 03:10:45 字数 634 浏览 3 评论 0 原文

我不完全明白 Node.js 的全部内容。也许是因为我主要是一个基于网络的业务应用程序开发人员。它是什么以及它有什么用?

到目前为止我的理解是:

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

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

I don't fully get what Node.js is all about. Maybe it's because I am mainly a web based business application developer. What is it and what is the use of it?

My understanding so far is that:

  1. The programming model is event driven, especially the way it handles I/O.
  2. It uses JavaScript and the parser is V8.
  3. It can be easily used to create concurrent server applications.

Are my understandings correct? If yes, then what are the benefits of evented I/O, is it just more for the concurrency stuff? Also, is the direction of Node.js to become a framework like, JavaScript based (V8 based) programming model?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

枯叶蝶 2024-08-21 03:10:46

另外,不要忘记提及 Google 的 V8 非常快。它实际上将 JavaScript 代码转换为机器代码,并具有与编译后的二进制文件相匹配的性能。因此,与所有其他伟大的事情一样,它的速度非常快。

Also, do not forget to mention that Google's V8 is VERY fast. It actually converts the JavaScript code to machine code with the matched performance of compiled binary. So along with all the other great things, it's INSANELY fast.

我ぃ本無心為│何有愛 2024-08-21 03:10:46

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

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

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

是的

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

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

Q: The programming model is event driven, especially the way it handles I/O.

Correct. It uses call-backs, so any request to access the file system would cause a request to be sent to the file system and then Node.js would start processing its next request. It would only worry about the I/O request once it gets a response back from the file system, at which time it will run the callback code. However, it is possible to make synchronous I/O requests (that is, blocking requests). It is up to the developer to choose between asynchronous (callbacks) or synchronous (waiting).

Q: It uses JavaScript and the parser is V8.

Yes

Q: It can be easily used to create concurrent server applications.

Yes, although you'd need to hand-code quite a lot of JavaScript. It might be better to look at a framework, such as http://www.easynodejs.com/ - which comes with full online documentation and a sample application.

零崎曲识 2024-08-21 03:10:45

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

Node.js 在生产中肯定是可能的,但距离文档中看似承诺的“交钥匙”部署还很远。在 Node.js v0.6.x 中,“集群”已集成到平台中,提供了基本的构建块之一,但我的“product.js”脚本仍然有约 150 行逻辑来处理创建日志等内容对于“严肃的”生产服务,您还需要准备好限制传入连接并执行 Apache 为 PHP。公平地说,Ruby on Rails 确实存在这个问题。它可以通过两种互补的机制来解决:1)将 Ruby on Rails/Node.js 放在专用的 Web 服务器后面(用 C 编写并经过反复测试),例如 Nginx (或 Apache / < a href="http://en.wikipedia.org/wiki/Lighttpd" rel="nofollow noreferrer">Lighttd)。网络服务器可以有效地提供静态内容、访问日志记录、重写 URL、终止 SSL、强制执行访问规则,并管理多个子服务。对于命中实际节点服务的请求,Web 服务器会代理该请求。 2)使用像 Unicorn 这样的框架来管理工作进程,定期回收它们等。我已经尚未找到一个看起来完全成熟的 Node.js 服务框架;它可能存在,但我还没有找到它,并且仍在我的手卷“生产.js”中使用〜150行。

阅读像 Express 这样的框架,看起来标准做法就是通过一个万事通来提供一切服务Node.js 服务...“app.use(express.static(__dirname + '/public'))”。对于低负载服务和开发来说,这可能没问题。但是,一旦您尝试在服务上投入大量时间并让它 24/7 运行,您很快就会发现推动大型网站拥有良好烘焙、强化的 C 代码(如 Nginx 负责其网站并处理所有静态内容请求(...直到您设置 CDN,例如 Amazon CloudFront))。对于对此的幽默和毫不掩饰的负面看法,请参阅这个人

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

优点/缺点:

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

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

  • Pro :可扩展到数千个活动连接。非常快而且非常高效。对于 Web 队列来说,与 PHP 或 Ruby Pro 相比,这可能意味着所需的盒子数量减少 10 倍
  • :编写并行模式很容易。想象一下,您需要从 Memcached 获取三个(或 N)个 blob。在 PHP 中执行此操作...您是否刚刚编写了获取第一个 blob、然后是第二个、然后是第三个 blob 的代码?哇,那太慢了。有一个特殊的 PECL 模块可以解决 Memcached 的特定问题,但是如果您想要怎么办与数据库查询并行获取一些 Memcached 数据?在 Node.js 中,由于范例是异步的,因此让一个 Web 请求并行执行多个操作是很自然的。
  • 缺点:异步代码从根本上来说比同步代码更复杂,如果开发人员没有充分理解并发执行的实际含义,那么前期的学习曲线可能会很困难。尽管如此,它比编写任何类型的带锁定的多线程代码要困难得多。
  • 缺点:如果一个计算密集型请求运行了例如 100 毫秒,它将停止处理同一 Node.js 进程中正在处理的其他请求...又名,协作多任务。这可以通过 Web Workers 模式来缓解(剥离子流程来处理昂贵的任务)。或者,您可以使用大量 Node.js 工作线程,并且只让每个工作线程同时处理一个请求(仍然相当高效,因为没有进程回收)。
  • 缺点:运行生产系统比 Apache + PHP 等 CGI 模型复杂得多,< a href="http://en.wikipedia.org/wiki/Perl" rel="nofollow noreferrer">Perl, Ruby 等。未处理的异常将导致整个进程崩溃,需要逻辑来重新启动失败的工作线程(请参阅Ruby 等)。 org/docs/latest/api/cluster.html" rel="nofollow noreferrer">集群)。具有错误的本机代码的模块可能会导致进程严重崩溃。每当一个工作进程死亡时,它正在处理的任何请求都会被丢弃,因此一个有缺陷的 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)。

Helper / JavaScript Sugar:

  • Underscore.js - 使用这个。去做就对了。它使您的代码变得漂亮且可读,例如 _.isString() 和 _.isArray()。我不太确定否则如何编写安全代码。另外,对于增强的命令行功能,请查看我自己的 Underscore-CLI

异步模式模块:

  • Step - 一种非常优雅的方式来表达串行和并行操作的组合。我个人的推荐。请参阅我的帖子了解 Step 代码的样子。
  • Futures - 通过需求表达排序的更灵活(这真的是一件好事吗?)的方式。可以表达“并行启动a、b、c。当A、B完成后,启动AB。当A、C完成后,启动AC。”这种灵活性需要更加小心,以避免工作流程中出现错误(例如从不调用回调,或多次调用它)。请参阅 Raynos 的关于使用 futures 的文章(这篇文章让我“获得”期货)。
  • Async - 更传统的库,每种模式都有一种方法。在我虔诚地转向 Step 之前,我就开始了这一点,随后意识到 Async 中的所有模式都可以用一个更具可读性的范例在 Step 中表达。
  • TameJS - 由 OKCupid 编写,它是一个预编译器,添加了新的语言原语“await”,用于优雅地编写串行和并行工作流程。该模式看起来很棒,但它确实需要预编译。关于这一点我还在拿定主意。
  • StreamlineJS - TameJS 的竞争对手。我倾向于Tame,但你可以自己做决定。

或者要阅读有关异步库的所有信息,请参阅此小组访谈 与作者一起。

Web 框架:

测试:

  • JSHint - 必须使用;我一开始没有使用这个,现在看来难以理解。 JSLint 添加了使用 Java 等编译语言获得的一系列基本验证。括号不匹配、未声明的变量、多种形状和大小的打字。您还可以打开我所说的“肛门模式”的各种形式,您可以在其中验证空白的样式和诸如此类的东西,如果这是您喜欢的,那就没问题了——但真正的价值来自于获得有关确切行号的即时反馈,其中你忘记了结束符“)”......而不必运行你的代码并点击有问题的行。 “JSHint”是 Douglas CrockfordJSLint
  • Mocha 是我开始喜欢的 Vows 的竞争对手。这两个框架都能很好地处理基础知识,但复杂的模式往往更容易在 Mocha 中表达。
  • Vows Vows 确实非常优雅。它会打印出一份可爱的报告(--spec),显示哪些测试用例通过/失败。花 30 分钟学习它,您就可以轻松地为您的模块创建基本测试。
  • Zombie - 使用 JSDom 作为虚拟“浏览器”。非常强大的东西。将其与 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) 调度程序已经做了很多工作,但最终,单个事件驱动进程比竞争 CPU 时间的 10^6 个进程要高效得多。此外,在过载情况下,多进程模型的表现非常糟糕,导致关键的管理和管理服务匮乏,尤其是 SSHD(这意味着您甚至无法登录到盒子来弄清楚它到底有多糟糕)。

Node.js 是单线程并且无锁。 Node.js 作为一个经过深思熟虑的设计选择,每个进程只有一个线程。因此,多个线程根本不可能同时访问数据。因此,不需要锁。线程很难。真的真的很难。如果您不相信这一点,那么您还没有进行足够的线程编程。正确锁定是很困难的,并且会导致很难追踪的错误。消除锁和多线程可以让最令人讨厌的错误之一消失。这可能是节点的最大优势。

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

两种方法:

  1. 对于图像编码等大型繁重计算任务,Node.js 可以启动子进程或向额外的工作进程。在此设计中,您将有一个线程管理事件流,N 个进程执行繁重的计算任务并占用其他 15 个 CPU。
  2. 为了扩展 Web 服务的吞吐量,您应该在一个机器上运行多个 Node.js 服务器,每个核心一个,使用 cluster (对于 Node.js v0.6.x,此处链接的官方“集群”模块取代了具有不同 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 引擎(它不再是 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”变量不必是只读的。这种强大的语言功能使异步编程变得不再那么冗长和痛苦。

编写异步代码总是比编写简单的单线程脚本更复杂,但是使用 Node.js,这并没有那么困难,除了对数千个并发连接的效率和可扩展性之外,您还可以获得很多好处。 ..

I use Node.js at work, and find it to be very powerful. Forced to choose one word to describe Node.js, I'd say "interesting" (which is not a purely positive adjective). The community is vibrant and growing. JavaScript, despite its oddities can be a great language to code in. And you will daily rethink your own understanding of "best practice" and the patterns of well-structured code. There's an enormous energy of ideas flowing into Node.js right now, and working in it exposes you to all this thinking - great mental weightlifting.

Node.js in production is definitely possible, but far from the "turn-key" deployment seemingly promised by the documentation. With Node.js v0.6.x, "cluster" has been integrated into the platform, providing one of the essential building blocks, but my "production.js" script is still ~150 lines of logic to handle stuff like creating the log directory, recycling dead workers, etc. For a "serious" production service, you also need to be prepared to throttle incoming connections and do all the stuff that Apache does for PHP. To be fair, Ruby on Rails has this exact problem. It is solved via two complementary mechanisms: 1) Putting Ruby on Rails/Node.js behind a dedicated webserver (written in C and tested to hell and back) like Nginx (or Apache / Lighttd). The webserver can efficiently serve static content, access logging, rewrite URLs, terminate SSL, enforce access rules, and manage multiple sub-services. For requests that hit the actual node service, the webserver proxies the request through. 2) Using a framework like Unicorn that will manage the worker processes, recycle them periodically, etc. I've yet to find a Node.js serving framework that seems fully baked; it may exist, but I haven't found it yet and still use ~150 lines in my hand-rolled "production.js".

Reading frameworks like Express makes it seem like the standard practice is to just serve everything through one jack-of-all-trades Node.js service ... "app.use(express.static(__dirname + '/public'))". For lower-load services and development, that'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 quickly discover the motivations that push big sites to have well baked, hardened C-code like Nginx fronting their site and handling all of the static content requests (...until you set up a CDN, like Amazon CloudFront)). For a somewhat humorous and unabashedly negative take on this, see this guy.

Node.js is also finding more and more non-service uses. Even if you are using something else to serve web content, you might still use Node.js as a build tool, using npm modules to organize your code, Browserify to stitch it into a single asset, and uglify-js to minify it for deployment. For dealing with the web, JavaScript is a perfect impedance match and frequently that makes it the easiest route of attack. For example, if you want to grovel through a bunch of JSON response payloads, you should use my underscore-CLI module, the utility-belt of structured data.

Pros / Cons:

  • Pro: For a server guy, writing JavaScript on the backend has been a "gateway drug" to learning modern UI patterns. I no longer dread writing client code.
  • Pro: Tends to encourage proper error checking (err is returned by virtually all callbacks, nagging the programmer to handle it; also, async.js and other libraries handle the "fail if any of these subtasks fails" paradigm much better than typical synchronous code)
  • Pro: Some interesting and normally hard tasks become trivial - like getting status on tasks in flight, communicating between workers, or sharing cache state
  • Pro: Huge community and tons of great libraries based on a solid package manager (npm)
  • Con: JavaScript has no standard library. You get so used to importing functionality that it feels weird when you use JSON.parse or some other build in method that doesn't require adding an npm module. This means that there are five versions of everything. Even the modules included in the Node.js "core" have five more variants should you be unhappy with the default implementation. This leads to rapid evolution, but also some level of confusion.

Versus a simple one-process-per-request model (LAMP):

  • Pro: Scalable to thousands of active connections. Very fast and very efficient. For a web fleet, this could mean a 10X reduction in the number of boxes required versus PHP or Ruby
  • Pro: Writing parallel patterns is easy. Imagine that you need to fetch three (or N) blobs from Memcached. Do this in PHP ... did you just write code the fetches the first blob, then the second, then the third? Wow, that's slow. There's a special PECL module to fix that specific problem for Memcached, but what if you want to fetch some Memcached data in parallel with your database query? In Node.js, because the paradigm is asynchronous, having a web request do multiple things in parallel is very natural.
  • Con: Asynchronous code is fundamentally more complex than synchronous code, and the up-front learning curve can be hard for developers without a solid understanding of what concurrent execution actually means. Still, it's vastly less difficult than writing any kind of multithreaded code with locking.
  • Con: If a compute-intensive request runs for, for example, 100 ms, it will stall processing of other requests that are being handled in the same Node.js process ... AKA, cooperative-multitasking. This can be mitigated with the Web Workers pattern (spinning off a subprocess to deal with the expensive task). Alternatively, you could use a large number of Node.js workers and only let each one handle a single request concurrently (still fairly efficient because there is no process recycle).
  • Con: Running a production system is MUCH more complicated than a CGI model like Apache + PHP, Perl, Ruby, etc. Unhandled exceptions will bring down the entire process, necessitating logic to restart failed workers (see cluster). Modules with buggy native code can hard-crash the process. Whenever a worker dies, any requests it was handling are dropped, so one buggy API can easily degrade service for other cohosted APIs.

Versus writing a "real" service in Java / C# / C (C? really?)

  • Pro: Doing asynchronous in Node.js is easier than doing thread-safety anywhere else and arguably provides greater benefit. Node.js is by far the least painful asynchronous paradigm I've ever worked in. With good libraries, it is only slightly harder than writing synchronous code.
  • Pro: No multithreading / locking bugs. True, you invest up front in writing more verbose code that expresses a proper asynchronous workflow with no blocking operations. And you need to write some tests and get the thing to work (it is a scripting language and fat fingering variable names is only caught at unit-test time). BUT, once you get it to work, the surface area for heisenbugs -- strange problems that only manifest once in a million runs -- that surface area is just much much lower. The taxes writing Node.js code are heavily front-loaded into the coding phase. Then you tend to end up with stable code.
  • Pro: JavaScript is much more lightweight for expressing functionality. It's hard to prove this with words, but JSON, dynamic typing, lambda notation, prototypal inheritance, lightweight modules, whatever ... it just tends to take less code to express the same ideas.
  • Con: Maybe you really, really like coding services in Java?

For another perspective on JavaScript and Node.js, check out From Java to Node.js, a blog post on a Java developer's impressions and experiences learning Node.js.


Modules
When considering node, keep in mind that your choice of JavaScript libraries will DEFINE your experience. Most people use at least two, an asynchronous pattern helper (Step, Futures, Async), and a JavaScript sugar module (Underscore.js).

Helper / JavaScript Sugar:

  • Underscore.js - use this. Just do it. It makes your code nice and readable with stuff like _.isString(), and _.isArray(). I'm not really sure how you could write safe code otherwise. Also, for enhanced command-line-fu, check out my own Underscore-CLI.

Asynchronous Pattern Modules:

  • Step - a very elegant way to express combinations of serial and parallel actions. My personal reccomendation. See my post on what Step code looks like.
  • Futures - much more flexible (is that really a good thing?) way to express ordering through requirements. Can express things like "start a, b, c in parallel. When A, and B finish, start AB. When A, and C finish, start AC." Such flexibility requires more care to avoid bugs in your workflow (like never calling the callback, or calling it multiple times). See Raynos's post on using futures (this is the post that made me "get" futures).
  • Async - more traditional library with one method for each pattern. I started with this before my religious conversion to step and subsequent realization that all patterns in Async could be expressed in Step with a single more readable paradigm.
  • TameJS - Written by OKCupid, it's a precompiler that adds a new language primative "await" for elegantly writing serial and parallel workflows. The pattern looks amazing, but it does require pre-compilation. I'm still making up my mind on this one.
  • StreamlineJS - competitor to TameJS. I'm leaning toward Tame, but you can make up your own mind.

Or to read all about the asynchronous libraries, see this panel-interview with the authors.

Web Framework:

  • Express Great Ruby on Rails-esk framework for organizing web sites. It uses JADE as a XML/HTML templating engine, which makes building HTML far less painful, almost elegant even.
  • jQuery While not technically a node module, jQuery is quickly becoming a de-facto standard for client-side user interface. jQuery provides CSS-like selectors to 'query' for sets of DOM elements that can then be operated on (set handlers, properties, styles, etc). Along the same vein, Twitter's Bootstrap CSS framework, Backbone.js for an MVC pattern, and Browserify.js to stitch all your JavaScript files into a single file. These modules are all becoming de-facto standards so you should at least check them out if you haven't heard of them.

Testing:

  • JSHint - Must use; I didn't use this at first which now seems incomprehensible. JSLint adds back a bunch of the basic verifications you get with a compiled language like Java. Mismatched parenthesis, undeclared variables, typeos of many shapes and sizes. You can also turn on various forms of what I call "anal mode" where you verify style of whitespace and whatnot, which is OK if that's your cup of tea -- but the real value comes from getting instant feedback on the exact line number where you forgot a closing ")" ... without having to run your code and hit the offending line. "JSHint" is a more-configurable variant of Douglas Crockford's JSLint.
  • Mocha competitor to Vows which I'm starting to prefer. Both frameworks handle the basics well enough, but complex patterns tend to be easier to express in Mocha.
  • Vows Vows is really quite elegant. And it prints out a lovely report (--spec) showing you which test cases passed / failed. Spend 30 minutes learning it, and you can create basic tests for your modules with minimal effort.
  • Zombie - Headless testing for HTML and JavaScript using JSDom as a virtual "browser". Very powerful stuff. Combine it with Replay to get lightning fast deterministic tests of in-browser code.
  • A comment on how to "think about" testing:
    • Testing is non-optional. With a dynamic language like JavaScript, there are very few static checks. For example, passing two parameters to a method that expects 4 won't break until the code is executed. Pretty low bar for creating bugs in JavaScript. Basic tests are essential to making up the verification gap with compiled languages.
    • Forget validation, just make your code execute. For every method, my first validation case is "nothing breaks", and that'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 find yourself going back and adding the nuanced validation cases you skipped.
    • Start small and break the inertial barrier. We are all lazy, and pressed for time, and it's easy to see testing as "extra work". So start small. Write test case 0 - load your module and report success. If you force yourself to do just this much, then the inertial barrier to testing is broken. That's <30 min to do it your first time, including reading the documentation. Now write test case 1 - call one of your methods and verify "nothing breaks", that is, that you don't get an error back. Test case 1 should take you less than one minute. With the inertia gone, it becomes easy to incrementally expand your test coverage.
    • Now evolve your tests with your code. Don't get intimidated by what the "correct" end-to-end test would look like with mock servers and all that. Code starts simple and evolves to handle new cases; tests should too. As you add new cases and new complexity to your code, add test cases to exercise the new code. As you find bugs, add verifications and / or new cases to cover the flawed code. When you are debugging and lose confidence in a piece of code, go back and add tests to prove that it is doing what you think it is. Capture strings of example data (from other services you call, websites you scrape, whatever) and feed them to your parsing code. A few cases here, improved validation there, and you will end up with highly reliable code.

Also, check out the official list of recommended Node.js modules. However, GitHub's Node Modules Wiki is much more complete and a good resource.


To understand Node, it's helpful to consider a few of the key design choices:

Node.js is EVENT BASED and ASYNCHRONOUS / NON-BLOCKING. Events, like an incoming HTTP connection will fire off a JavaScript function that does a little bit of work and kicks off other asynchronous tasks like connecting to a database or pulling content from another server. Once these tasks have been kicked off, the event function finishes and Node.js goes back to sleep. As soon as something else happens, like the database connection being established or the external server responding with content, the callback functions fire, and more JavaScript code executes, potentially kicking off even more asynchronous tasks (like a database query). In this way, Node.js will happily interleave activities for multiple parallel workflows, running whatever activities are unblocked at any point in time. This is why Node.js does such a great job managing thousands of simultaneous connections.

Why not just use one process/thread per connection like everyone else? In Node.js, a new connection is just a very small heap allocation. Spinning up a new process takes significantly more memory, a megabyte on some platforms. But the real cost is the overhead associated with context-switching. When you have 10^6 kernel threads, the kernel has to do a lot of work figuring out who should execute next. A bunch of work has gone into building an O(1) scheduler for Linux, but in the end, it's just way way more efficient to have a single event-driven process than 10^6 processes competing for CPU time. Also, under overload conditions, the multi-process model behaves very poorly, starving critical administration and management services, especially SSHD (meaning you can't even log into the box to figure out how screwed it really is).

Node.js is SINGLE THREADED and LOCK FREE. Node.js, as a very deliberate design choice only has a single thread per process. Because of this, it's fundamentally impossible for multiple threads to access data simultaneously. Thus, no locks are needed. Threads are hard. Really really hard. If you don't believe that, you haven't done enough threaded programming. Getting locking right is hard and results in bugs that are really hard to track down. Eliminating locks and multi-threading makes one of the nastiest classes of bugs just go away. This might be the single biggest advantage of node.

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

Two ways:

  1. For big heavy compute tasks like image encoding, Node.js can fire up child processes or send messages to additional worker processes. In this design, you'd have one thread managing the flow of events and N processes doing heavy compute tasks and chewing up the other 15 CPUs.
  2. For scaling throughput on a webservice, you should run multiple Node.js servers on one box, one per core, using cluster (With Node.js v0.6.x, the official "cluster" module linked here replaces the learnboost version which has a different API). These local Node.js servers can then compete on a socket to accept new connections, balancing load across them. Once a connection is accepted, it becomes tightly bound to a single one of these shared processes. In theory, this sounds bad, but in practice it works quite well and allows you to avoid the headache of writing thread-safe code. Also, this means that Node.js gets excellent CPU cache affinity, more effectively using memory bandwidth.

Node.js lets you do some really powerful things without breaking a sweat. Suppose you have a Node.js program that does a variety of tasks, listens on a TCP port for commands, encodes some images, whatever. With five lines of code, you can add in an HTTP based web management portal that shows the current status of active tasks. This is EASY to do:

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");

Now you can hit a URL and check the status of your running process. Add a few buttons, and you have a "management portal". If you have a running Perl / Python / Ruby script, just "throwing in a management portal" isn't exactly simple.

But isn't JavaScript slow / bad / evil / spawn-of-the-devil? JavaScript has some weird oddities, but with "the good parts" there's a very powerful language there, and in any case, JavaScript is THE language on the client (browser). JavaScript is here to stay; other languages are targeting it as an IL, and world class talent is competing to produce the most advanced JavaScript engines. Because of JavaScript's role in the browser, an enormous amount of engineering effort is being thrown at making JavaScript blazing fast. V8 is the latest and greatest javascript engine, at least for this month. It blows away the other scripting languages in both efficiency AND stability (looking at you, Ruby). And it'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's no longer a JavaScript "interpreter" as all the modern engines do tons of JIT compiling under the hood with interpretation only as a fallback for execute-once code). Yeah, we all wish we could fix a few of the odder JavaScript language choices, but it's really not that bad. And the language is so darn flexible that you really aren't coding JavaScript, you are coding Step or jQuery -- more than any other language, in JavaScript, the libraries define the experience. To build web applications, you pretty much have to know JavaScript anyway, so coding with it on the server has a sort of skill-set synergy. It has made me not dread writing client code.

Besides, if you REALLY hate JavaScript, you can use syntactic sugar like CoffeeScript. Or anything else that creates JavaScript code, like Google Web Toolkit (GWT).

Speaking of JavaScript, what's a "closure"? - Pretty much a fancy way of saying that you retain lexically scoped variables across call chains. ;) Like this:

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();

See how you can just use "myData" without doing anything awkward like stashing it into an object? And unlike in Java, the "myData" variable doesn't have to be read-only. This powerful language feature makes asynchronous-programming much less verbose and less painful.

Writing asynchronous code is always going to be more complex than writing a simple single-threaded script, but with Node.js, it's not that much harder and you get a lot of benefits in addition to the efficiency and scalability to thousands of concurrent connections...

凉风有信 2024-08-21 03:10:45

我认为优点是:

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

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

    能够

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

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

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

I think the advantages are:

  1. Web development in a dynamic language (JavaScript) on a VM that is incredibly fast (V8). It is much faster than Ruby, Python, or Perl.

  2. Ability to handle thousands of concurrent connections with minimal overhead on a single process.

  3. JavaScript is perfect for event loops with first class function objects and closures. People already know how to use it this way having used it in the browser to respond to user initiated events.

  4. A lot of people already know JavaScript, even people who do not claim to be programmers. It is arguably the most popular programming language.

  5. Using JavaScript on a web server as well as the browser reduces the impedance mismatch between the two programming environments which can communicate data structures via JSON that work the same on both sides of the equation. Duplicate form validation code can be shared between server and client, etc.

你列表最软的妹 2024-08-21 03:10:45

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 确实令人兴奋 这是我对库/平台的介绍...我发现它非常好。

V8 is an implementation of JavaScript. It lets you run standalone JavaScript applications (among other things).

Node.js is simply a library written for V8 which does evented I/O. This concept is a bit trickier to explain, and I'm sure someone will answer with a better explanation than I... The gist is that rather than doing some input or output and waiting for it to happen, you just don't wait for it to finish. So for example, ask for the last edited time of a file:

// Pseudo code
stat( 'somefile' )

That might take a couple of milliseconds, or it might take seconds. With evented I/O you simply fire off the request and instead of waiting around you attach a callback that gets run when the request finishes:

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

This makes it a lot like JavaScript code in the browser (for example, with Ajax style functionality).

For more information, you should check out the article Node.js is genuinely exciting which was my introduction to the library/platform... I found it quite good.

云雾 2024-08-21 03:10:45

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

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

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

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

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

Node.js is an open source command line tool built for the server side JavaScript code. You can download a tarball, compile and install the source. It lets you run JavaScript programs.

The JavaScript is executed by the V8, a JavaScript engine developed by Google which is used in Chrome browser. It uses a JavaScript API to access the network and file system.

It is popular for its performance and the ability to perform parallel operations.

Understanding node.js is the best explanation of node.js I have found so far.

Following are some good articles on the topic.

情话已封尘 2024-08-21 03:10:45

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

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

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

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

The closures are a way to execute code in the context it was created in.

What this means for concurency is that you can define variables, then initiate a nonblocking I/O function, and send it an anonymous function for its callback.

When the task is complete, the callback function will execute in the context with the variables, this is the closure.

The reason closures are so good for writing applications with nonblocking I/O is that it's very easy to manage the context of functions executing asynchronously.

感情旳空白 2024-08-21 03:10:45

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

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

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

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

另一个很好的例子是,您可以使用同一段代码使您的网页与打开或关闭的 JavaScript 兼容。想象一下,您有一个用 JavaScript 进行的日期选择,允许您的用户使用日历选择任何日期。您可以编写(或使用)同一段 JavaScript 代码,使其在打开或关闭 JavaScript 的情况下工作。

Two good examples are regarding how you manage templates and use progressive enhancements with it. You just need a few lightweight pieces of JavaScript code to make it work perfectly.

I strongly recommend that you watch and read these articles:

Pick up any language and try to remember how you would manage your HTML file templates and what you had to do to update a single CSS class name in your DOM structure (for instance, a user clicked on a menu item and you want that marked as "selected" and update the content of the page).

With Node.js it is as simple as doing it in client-side JavaScript code. Get your DOM node and apply your CSS class to that. Get your DOM node and innerHTML your content (you will need some additional JavaScript code to do this. Read the article to know more).

Another good example, is that you can make your web page compatible both with JavaScript turned on or off with the same piece of code. Imagine you have a date selection made in JavaScript that would allow your users to pick up any date using a calendar. You can write (or use) the same piece of JavaScript code to make it work with your JavaScript turned ON or OFF.

人事已非 2024-08-21 03:10:45

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

这里是一个总结:

如果快餐店采用传统的基于线程的模式,您将点完食物并排队等候,直到收到食物。在您的订单完成之前,您后面的人将无法订购。在事件驱动模型中,您点了食物,然后插队等待。然后其他人都可以自由订购。

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

  • 您使用 Web 浏览器在
    Node.js Web 服务器。

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

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

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

  • Node.js 服务器执行该函数,在本例中将
    渲染“/about.html”页面并将其发送回您的 Web 浏览器。”

There is a very good fast food place analogy that best explains the event driven model of Node.js, see the full article, Node.js, Doctor’s Offices and Fast Food Restaurants – Understanding Event-driven Programming

Here is a summary:

If the fast food joint followed a traditional thread-based model, you'd order your food and wait in line until you received it. The person behind you wouldn't be able to order until your order was done. In an event-driven model, you order your food and then get out of line to wait. Everyone else is then free to order.

Node.js is event-driven, but most web servers are thread-based.York explains how Node.js works:

  • You use your web browser to make a request for "/about.html" on a
    Node.js web server.

  • The Node.js server accepts your request and calls a function to retrieve
    that file from disk.

  • While the Node.js server is waiting for the file to be retrieved, it
    services the next web request.

  • When the file is retrieved, there is a callback function that is
    inserted in the Node.js servers queue.

  • The Node.js server executes that function which in this case would
    render the "/about.html" page and send it back to your web browser."

潦草背影 2024-08-21 03:10:45

嗯,我明白

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

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

Well, I understand that

  • Node's goal is to provide an easy way
    to build scalable network programs.
  • Node is similar in design to and influenced by systems like Ruby's Event Machine or Python's Twisted.
  • Evented I/O for V8 javascript.

For me that means that you were correct in all three assumptions. The library sure looks promising!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文