我不完全了解Node.js的全部内容。也许是因为我主要是基于 Web 的业务应用程序开发人员。它是什么以及它的用途是什么?
到目前为止,我的理解是:
- 编程模型是事件驱动的,尤其是它处理I/O 的方式。
- 它使用JavaScript,解析器是V8。
- 它可以很容易地用于创建并发服务器应用程序。
我的理解正确吗?如果是,那么事件化 I/O 的好处是什么,它是否只是为了并发性?另外,Node.js 的发展方向是像基于 JavaScript(基于 V8)的编程模型那样的框架吗?
我不完全了解Node.js的全部内容。也许是因为我主要是基于 Web 的业务应用程序开发人员。它是什么以及它的用途是什么?
到目前为止,我的理解是:
我的理解正确吗?如果是,那么事件化 I/O 的好处是什么,它是否只是为了并发性?另外,Node.js 的发展方向是像基于 JavaScript(基于 V8)的编程模型那样的框架吗?
我在工作中使用 Node.js,发现它非常强大。被迫选择一个词来描述 Node.js,我会说“有趣”(这不是一个纯粹的积极形容词)。社区充满活力且不断发展。尽管 JavaScript 很奇怪,但它仍然是一种很好的编码语言。您每天都会重新思考自己对“最佳实践”和结构良好代码模式的理解。现在有大量的想法流入 Node.js,在其中工作会让你接触到所有这些想法 - 伟大的精神举重。
生产中的 Node.js 绝对是可能的,但与文档中似乎Promise的“交钥匙”部署相去甚远。在 Node.js v0.6.x 中,“集群”已集成到平台中,提供了基本构建块之一,但我的“production.js”脚本仍然有大约 150 行逻辑来处理诸如创建日志之类的事情目录、回收死去的工人等。对于“严肃”的生产服务,您还需要准备好限制传入的连接并执行 Apache 为PHP所做的所有事情。公平地说,Ruby on Rails确实存在这个问题。它通过两种互补机制解决:1) 将 Ruby on Rails/Node.apache/ Lighttd)。Web 服务器可以有效地提供静态内容、访问日志记录、重写 URL、终止SSL、执行访问规则和管理多个子服务。对于命中实际节点服务的请求,网络服务器会代理该请求。2)使用像Unicorn这样的框架来管理工作进程,定期回收它们等等。我还没有找到一个看起来完全成熟的 Node.js 服务框架;它可能存在,但我还没有找到它,并且仍然在我手工制作的“production.js”中使用了大约 150 行。
阅读像Express这样的框架,似乎标准的做法是通过一个万能的 Node.js 服务来提供一切服务......“app.use(express.static(__dirname + '/public'))” . 对于低负载的服务和开发,这可能没问题。但是,一旦您尝试将大量时间加载到您的服务上并让它 24/7 全天候运行,您就会很快发现推动大型站点拥有完善的、强化的 C 代码(如Nginx位于其站点的前端并处理所有内容的动机)静态内容请求(...直到您设置CDN,如Amazon CloudFront))。对于这个有点幽默和毫不掩饰的负面看法,看看这个人。
Node.js 也发现了越来越多的非服务用途。即使您使用其他东西来提供 Web 内容,您仍然可以使用 Node.js 作为构建工具,使用npmmodule来组织您的代码,使用Browserify将其拼接成单个资产,并使用uglify-js将其缩小以进行部署. 对于处理网络,JavaScript 是一种完美的阻抗匹配,并且经常使其成为最简单的攻击途径。例如,如果您想通过一堆JSON响应有效负载进行探索,您应该使用我的underscore-CLImodule,即结构化数据的实用程序带。
有关 JavaScript 和 Node.js 的另一个观点,请查看从 Java 到 Node.js,这是一篇关于 Java 开发人员学习 Node.js 的印象和经验的博客文章。
module 在考虑 node 时,请记住您选择的 JavaScript 库将定义您的体验。大多数人至少使用两个,一个异步模式助手(Step、Futures、Async)和一个 JavaScript 糖module(Underscore.js)。
助手 / JavaScript 糖:
异步模式module:
或者要阅读有关异步库的所有信息,请参阅与作者的小组访谈。
网络框架:
测试:
此外,请查看推荐的 Node.js module的官方列表。但是,GitHub 的 Node Modules Wiki更加完整,并且是一个很好的资源。
要理解 Node,考虑一些关键的设计选择会很有帮助:
Node.js 是基于事件和异步/非阻塞的. 事件(如传入的 HTTP 连接)将触发 JavaScript 函数,该函数执行一些工作并启动其他异步任务,如连接到数据库或从另一台服务器提取内容。一旦这些任务被启动,事件函数就会结束,Node.js 会重新进入睡眠状态。一旦发生其他事情,比如建立数据库连接或外部服务器响应内容,回调函数就会触发,更多的 JavaScript 代码执行,可能会启动更多的异步任务(比如数据库查询)。通过这种方式,Node.js 将愉快地为多个并行工作流交错活动,在任何时间点运行任何不受阻止的活动。这就是 Node.js 在管理数千个并发连接方面做得如此出色的原因。
为什么不像其他人一样为每个连接使用一个进程/线程?在 Node.js 中,一个新的连接只是一个非常小的堆分配。启动一个新进程需要更多的内存,在某些平台上为 MB。但真正的成本是与上下文切换相关的开销。当您有 10^6 个内核线程时,内核必须做很多工作来确定下一个应该执行谁。为 Linux 构建 O(1) 调度程序已经进行了大量工作,但最终,与 10^6 个进程竞争 CPU 时间相比,拥有单个事件驱动进程的效率更高。此外,在过载情况下,多进程模型的表现非常糟糕,关键的管理和管理服务匮乏,尤其是 SSHD(这意味着您甚至无法登录盒子以了解它到底有多糟糕)。
Node.js 是单线程和无锁的。Node.js,作为一个非常深思熟虑的设计选择,每个进程只有一个线程。因此,多个线程同时访问数据从根本上是不可能的。因此,不需要锁。线程很难。真的真的很难。如果您不相信这一点,那么您还没有完成足够的线程编程。正确锁定很难,并且会导致很难追踪的错误。消除锁和多线程使最严重的错误类别之一消失了。这可能是 node.js 的最大优势。
但是我如何利用我的 16 核盒子呢?
两种方式:
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,它并没有那么难,除了效率和数千个并发连接的可扩展性之外,您还可以获得很多好处。 ..
我认为优点是:
在 VM 上使用动态语言 (JavaScript) 进行 Web 开发,速度非常快 (V8)。它比 Ruby、Python 或 Perl 快得多。
能够在单个进程上以最小的开销处理数千个并发连接。
JavaScript 非常适合具有一流函数对象和闭包的事件循环。人们已经知道如何以这种方式使用它,在浏览器中使用它来响应用户发起的事件。
很多人已经知道 JavaScript,即使是那些不自称是程序员的人。它可以说是最流行的编程语言。
在 Web 服务器和浏览器上使用 JavaScript 可以减少两种编程环境之间的阻抗失配,这两种编程环境可以通过 JSON 通信数据结构,在等式两边工作相同。重复的表单验证代码可以在服务器和客户端等之间共享。
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 真的令人兴奋,这是我对库/平台的介绍......我发现它非常好。
闭包是在创建代码的上下文中执行代码的一种方式。
这对于并发性意味着您可以定义变量,然后启动一个非阻塞I/O函数,并为其回调发送一个匿名函数。
当任务完成时,回调函数将在带有变量的上下文中执行,这就是闭包。
闭包非常适合编写具有非阻塞 I/O 的应用程序的原因是它非常容易管理异步执行的函数的上下文。