我没有完全了解Node.js的全部内容.也许是因为我主要是一个基于Web的业务应用程序开发人员.它是什么以及它的用途是什么?
到目前为止,我的理解是:
编程模型是事件驱动的,尤其是它处理I/O的方式.
它使用JavaScript,解析器是V8.
它可以很容易地用于创建并发服务器应用程序.
我的理解是否正确?如果是,那么即使I/O有什么好处,它对于并发性的东西更多吗?另外,Node.js的方向是成为一个类似于基于JavaScript(V8的)编程模型的框架吗?
我在工作中使用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放在Rails/Node上.Apache/Lighttd).Web服务器可以有效地提供静态内容,访问日志记录,重写URL,终止SSL,实施访问规则以及管理多个子服务.对于访问实际节点服务的请求,Web服务器代理请求.2)使用像Unicorn这样的框架来管理工作进程,定期回收它们等等.我还没有找到一个看似完全烘焙的Node.js服务框架; 它可能存在,但我还没有找到它,仍然在我的手工卷"production.js"中使用~150行.
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.
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没有标准库.当你使用JSON.parse或其他一些不需要添加npm模块的方法时,你已经习惯了导入功能,感觉很奇怪.这意味着一切都有五个版本.如果您对默认实现不满意,即使Node.js"核心"中包含的模块还有五个变体.这导致快速进化,但也有一定程度的混乱.
Pro:可扩展到数千个活动连接.非常快速且非常高效.对于网络车队来说,这意味着与PHP或Ruby相比,所需的箱数减少了10倍
Pro:编写并行模式很容易.想象一下,你需要从Memcached中获取三个(或N个)blob .在PHP中执行此操作...您是否只编写了获取第一个blob的代码,然后是第二个,然后是第三个?哇,那很慢.有一个特殊的PECL模块来修复Memcached的特定问题,但是如果你想要与数据库查询并行获取一些Memcached数据呢?在Node.js中,因为范例是异步的,所以具有web请求并行执行多个操作是非常自然的.
Con:异步代码基本上比同步代码更复杂,如果没有对并发执行实际意味着什么的充分理解,开发人员的前期学习曲线可能很难.但是,与使用锁定编写任何类型的多线程代码相比,它要困难得多.
Con:如果计算密集型请求运行(例如,100 ms),它将停止处理在同一Node.js进程中处理的其他请求... AKA,合作多任务.这可以通过Web Workers模式(关闭子流程来处理昂贵的任务)来缓解.或者,您可以使用大量Node.js工作程序,并且只让每个工作程序同时处理单个请求(仍然相当有效,因为没有进程回收).
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.
Pro:在Node.js中进行异步操作比在其他地方进行线程安全更容易,并且可以提供更大的好处.到目前为止,Node.js是我曾经工作过的最不痛苦的异步范例.使用好的库,它只比编写同步代码稍微困难一些.
亲:没有多线程/锁定错误.没错,您可以在编写更详细的代码时进行投资,这些代码表达了一个没有阻塞操作的正确的异步工作流.并且您需要编写一些测试并使其工作(它是一种脚本语言,并且指法变量名称仅在单元测试时捕获).但是,一旦你开始工作,heisenbugs的表面区域- 奇怪的问题只出现在一百万次运行中 - 表面积要低得多.编写Node.js代码的税收严重加载到编码阶段.然后你倾向于最终得到稳定的代码.
Pro:JavaScript表达功能要轻得多.很难用文字来证明这一点,但JSON,动态类型,lambda表示法,原型继承,轻量级模块,等等......它只是用较少的代码来表达相同的想法.
Con:也许你真的非常喜欢Java中的编码服务?
有关JavaScript和Node.js的另一个视角,请查看从Java到Node.js,这是一篇关于Java开发人员学习Node.js的印象和经验的博客文章.
模块 在考虑节点时,请记住,您选择的JavaScript库将定义您的体验.大多数人使用至少两个,一个异步模式助手(Step,Futures,Async)和一个JavaScript糖模块(Underscore.js).
助手/ JavaScript糖:
Underscore.js - 使用它.去做就对了.它使用_.isString()和_.isArray()之类的东西使代码变得美观可读.我不确定如何编写安全代码.另外,对于增强的命令行fu,请查看我自己的Underscore-CLI.
异步模式模块:
步骤 - 表达串行和并行动作组合的非常优雅的方式.我的个人推荐.请参阅我的帖子,了解Step代码的含义.
期货 - 更灵活(这真的是一件好事吗?)通过要求表达订单的方式.可以表达诸如"并行启动a,b,c."当A和B完成时,启动AB.当A和C完成时,启动AC.这种灵活性需要更加小心,以避免工作流中的错误(例如从不调用回调,或多次调用它).请参阅Raynos关于使用期货的帖子(这是让我"获得"期货的帖子).
异步 - 更传统的库,每种模式都有一种方法.我在开始宗教转换之前开始使用这个步骤,然后意识到Async中的所有模式都可以用一个更易读的范例来表达.
TameJS - 由OKCupid编写,它是一个预编译器,为优雅编写串行和并行工作流程添加了一种新的语言"等待".该模式看起来很神奇,但确实需要预编译.我还在决定这个.
StreamlineJS - TameJS的竞争对手.我倾向于驯服,但你可以自己决定.
或者阅读有关异步库的所有内容,请参阅此面板 -与作者的访谈.
Web框架:
Express Great Ruby on Rails-esk框架,用于组织网站.它使用JADE作为XML/HTML模板引擎,这使得构建HTML变得更加痛苦,甚至更加优雅.
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:
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.
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 l
我认为其优点是:
在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真正令人兴奋,这是我对库/平台的介绍...我发现它非常好.
Node.js是一个为服务器端JavaScript代码构建的开源命令行工具.您可以下载tarball,编译并安装源代码.它允许您运行JavaScript程序.
JavaScript由V8执行,V8是由Google开发的JavaScript引擎,用于Chrome浏览器.它使用JavaScript API来访问网络和文件系统.
它的性能和执行并行操作的能力很受欢迎.
理解node.js是我到目前为止找到的node.js的最佳解释.
以下是关于该主题的一些好文章.
使用Node.js学习服务器端JavaScript
这一次,你将学习Node.js
闭包是一种在创建它的上下文中执行代码的方法.
这意味着你可以定义变量,然后启动非阻塞I/O函数,并为其回调发送一个匿名函数.
当任务完成后,回调函数将在带有变量的上下文中执行,这就是闭包.
闭包非常适合编写具有非阻塞I/O的应用程序,因为管理异步执行的函数的上下文非常容易.
两个很好的例子是关于如何管理模板和使用渐进增强功能.您只需要一些轻量级的JavaScript代码即可使其完美运行.
我强烈建议您观看和阅读这些文章:
视频玻璃节点
Node.js YUI DOM操作
选择任何语言并尝试记住如何管理HTML文件模板以及在DOM结构中更新单个CSS类名称时必须执行的操作(例如,用户单击菜单项并且您希望将其标记为"选中"并更新页面内容).
使用Node.js就像在客户端JavaScript代码中一样简单.获取您的DOM节点并将CSS类应用于该节点.获取您的DOM节点和innerHTML您的内容(您将需要一些额外的JavaScript代码来执行此操作.阅读文章以了解更多信息).
另一个很好的例子是,您可以使用相同的代码打开或关闭JavaScript,使您的网页兼容.想象一下,您有一个用JavaScript制作的日期选择,允许您的用户使用日历获取任何日期.您可以编写(或使用)相同的JavaScript代码,以使其与您打开或关闭JavaScript一起使用.
有一个非常好的快餐店类比,最能说明Node.js的事件驱动模型,请参阅完整的文章,Node.js,Doctor's Offices和Fast Food Restaurants - 了解事件驱动的编程
以下是摘要:
如果快餐联合会遵循传统的基于线程的模式,您可以订购食物并排队等候直到收到它.在您的订单完成之前,您身后的人将无法订购.在事件驱动的模型中,您订购食物然后离开等待.然后其他人都可以自由订购.
Node.js是事件驱动的,但大多数Web服务器都是基于线程的.York解释了Node.js的工作原理:
您使用Web浏览器在Node.js Web服务器上发出"/about.html"请求.
Node.js服务器接受您的请求并调用函数从磁盘检索该文件.
当Node.js服务器正在等待检索文件时,它会为下一个Web请求提供服务.
检索文件时,会有一个插入Node.js服务器队列的回调函数.
Node.js服务器执行该功能,在这种情况下,该功能将呈现"/about.html"页面并将其发送回您的Web浏览器."
好吧,我明白了
Node的目标是提供一种简单的方法来构建可扩展的网络程序.
Node在设计上类似于Ruby的Event Machine或Python的Twisted等系统.
针对V8 javascript的求偶I/O.
对我而言,这意味着你在所有三个假设中都是正确的.图书馆看起来很有前途!
此外,不要忘记提到谷歌的V8非常快.它实际上将JavaScript代码转换为具有已编译二进制文件的匹配性能的机器代码.因此,除了所有其他伟大的东西,它是无助的快速.