我为什么向后端工程师推荐Nodejs

  百度云物可视无缝对接海量实时数据,零编程设计可视化仪表盘,完美支持监控大屏展现,更有强大的定制和嵌入功能,让开发数据可视化应用如此简单。本次沙龙主要分享物可视解决方案的数据源与数据流创建、仪表盘制作、部署,教你一键完成物可视服务的配置。

  百度云物可视无缝对接海量实时数据,零编程设计可视化仪表盘,完美支持监控大屏展现,更有强大的定制和嵌入功能,让开发数据可视化应用如此简单。本次沙龙主要分享物可视解决方案的数据源与数据流创建、仪表盘制作、部署,教你一键完成物可视服务的配置。

  //根据ID,在数据库中Persons表中查出Name var name = db.query(select name from persons where id=1); //进程等待数据查询完毕,然后使用查询结果。 output(name)

  这段代码的问题是在上面两个语句之间,在整个数据查询的过程中,当前程序进程往往只是在等待结果的返回.这就造成了进程的阻塞.对于高并发,I/O密集行的网络应用中,一方面进程很长时间处于等待状态,另一方面为了应付新的请求不断的增加新的进程.这样的浪费会导致系统支持QPS远远小于后端数据服务能够支撑的QPS,成为了系统的瓶颈.而且这样的系统也特别容易被慢链接攻击(客户端故意不接收或减缓接收数据,加长进程等待时间)。

  首先JavaScript是一种函数式编程语言,函数编程语言最重要的数学基础是演算(lambda calculus) -- 即函数对象可以作为其他函数对象的输入(参数)和输出(返回值)。

  这个特性使得为事件指定回调函数变得很容易。特别是JavaScript还支持匿名函数。通过匿名函数的辅助,之前的代码可以进行简写如下:

  细心的朋友可能已经注意到,当等待了n秒数据查询结果返回后执行回调时。回调函数中却仍然使用了main函数的局部变量id,而id似乎应该在n秒前走出其作用域。为什么此时id仍然可以访问呢,这是因为JavaScript的另外一个重要语言特性:闭包(Closures)。接下来我来详解闭包的原委。

  在复杂的应用中,我们一定会遇到这类场景。即在函数运行时需要访问函数定义时的上下文数据(注意:一定要区分函数定义时和函数运行时两个不同的时刻)。特别是在异步编程模型中,函数的定义和运行又分处不同的时间段,那么保持上下文的问题变得更加突出了。因为我们在任务执行一半时把资源交出去没有问题,但当任务需要再次继续时我们必须还原现场。

  记住这种重要的思路,我们再看看是否还能进一步的抽象?可以的,不过接下的动作之前,我们还要了解在JavaScript中一个函数也是一个对象。一个函数实例fn除了函数体的定义之外,我们仍然可以在这个函数对象实例之本身扩展其他属性,如fn.a=1;受到这个启发我们尝试把需要保持的状态直接绑定到函数实例上:

  其中变量对象VO,包含了所有局部变量的引用。对于main函数,局部变量id存储在VO.id内。看起来用VO来代替我们的currentSate最合适了。但main函数还可能嵌套在其他函数之内,所以我们需要ScopeChain,它是一个包含当前运行函数VO和其所有父函数scope的数组。

  所以在这个例子中,在onDataLoad函数定义时,就为默认为其绑定了一个[[scope]]属性指向其父函数的ExecutionContext的ScopeChain。而当函数onDataLoad执行时,就可以通过[[scope]]属性来访问父函数的VO对象来找到id,如果父函数的VO中没有id这个属性,就再继续向上查找其祖先的VO对象,直到找到id这个属性或到达最外层返回undefined。也正是因为这个引用,造成VO的引用计数不为0,在走出作用域时,才不会被垃圾回收。

  在传统网页开发中,用户的状态通过请求传递到服务端,交由后端状态保持(类似交给db.query的currentSate)。而使用Ajax的网页,因为并未离开原页面,那么服务端只要负责校验用户提交的数据是否正确即可,发送错误,返回错误处相关信息即可,这就是所谓前端状态保持。可以看到这个场景里边服务端做的事情变少了,变纯粹了。正如我们的例子中db.query不再存储转发第三个state参数,变得更在轻量。

  Node.js性能真的是最好么?不用比较我们也可以得到结论,Node.js做无阻塞编程性能较难做到极致。何为极致?处理一个请求需要占用多少内存,多少cpu资源,多少带宽,有丁点浪费就不是极致。阻塞式编程浪费了大量进程资源只是在等待,导致大量内存和cpu的浪费。在这方面Node.js好很多,但也正是因为一些闭包等JavaScript内建机制也会导致资源的浪费,看下面的代码:

  我们在回调函数当中只设置一个断点,并不指明我们要访问哪个变量。然后我们在控制台监视一下,id和str都是可以拿到的。

  所以我来猜想一下,性能极端苛刻的场景,无阻塞是未来,但无阻塞发展下去,或者有更轻量的脚本引擎产生,或者JavaScript引擎可能要调整可以disable闭包,或者我们要通过给JS开发静态编译器在代码发布前自动优化我们的代码。

  最常见的JavaScript静态编译就是脚本压缩工具,在代码发布到线上之前,我们通过各种压缩工具,将代码压缩,达到减少网络传输量的问题。而在这个时间点,已经有越来越多的事情可做,比如:Google利用ClouserComplier提供的系列编译指令,让JavaScript更好的实现OO编程。也有GWT,CoffeeScript这样的项目,将其他语言编译为JavaScript。在淘宝我们在代码静态编译阶段来解决因JavaScript细粒度模块化改造引入各种性能问题,也用来对第三方提供JavaScript代码进行一定的安全检查。

  除了性能方面的担忧,使用Node.js进行编程增加了代码编写的复杂度。因为我们习惯于阻塞式编程的写法,切换到异步模式编程,往往对于太多多层次的callback函数嵌套弄得不知所措。老赵最近开发了项目JSCEX正是要解决这个问题,它让大家在遵守一些小的约定后,能够仍然保持同步编程的写法进行代码开发。写完的代码同样通过静态编译器编译成异步回调式模式的代码再交给JavaScript引擎执行。

  说了这么多,无阻塞编程要做的还远不止这些。首先需要一个高效的JS引擎,高效的事件池和线程池。另外几乎所有和Node.js交互的传统模块如文件系统,数据访问,HTTP解析,DNS解析都是阻塞式的,都需要额外改造。

  Node.js作者极其团队,正是认清问题所在以及JS解决这些问题方面的优势。基于Google开源的高效JavaScript引擎V8,贡献了大量的智慧和精力解决上述大部分问题后才有Node.js横空出世。

  本文主要的信息来自Node.js作者在JSConf09JSConf10上的分享。 而作为前端开发,着重讲了函数式编程,闭包对于无阻塞开发的重要意义。我期待这篇文章能够给前端和后端工程师都带来收获。

  同样作为前端开发,不得不再插几句,说说服务端JS能够解决的另一个问题:当前的Web开发前后端使用不同的语言,很多相同的业务逻辑要前后端分别用不同语言重复实现。比如越来越多重度依赖JavaScript的胖客户端应用,当客户浏览器禁用JavaScript时,则需要使用服务端语言将主业务流程再实现一次,这即是前端常说的”渐进增强”。

  当我们拥有了服务端JavaScript语言,我们自然就会想到能否利用Node.js做到”一次开发,渐进增强”。解决掉这个为小量用户,浪费大量时间的恼人的问题。这方面的实践,YAHOO仍然是先驱,早在一年多前开始YAHOO通过nodejs-yui3项目做了很多卓越的贡献,而淘宝自主开发的前端框架Kissy也有服务端运行的相关尝试。

  李穆,前端工程师,就职于淘宝广告技术部架构组,淘宝花名:李牧,专注淘宝广告引擎和业务系统前端开发。个人博客:

  byyu bingxing作为单线程的node.js在多核系统中本身还需要去手动的进行多线程均衡负载,而scala作为基于erlang轻量级线程Actor机制能够实现在语言级别就能支持多核性能的发挥,另加上akka中使用的netty的NIO模块,在单实例并发量的处理效率上据说akka是node.js的一个数量级的优势,因为没有测试过,所以不知道是否是这样的呢?”一次开发,渐进增强”确实是javascript开发后端的一大优势

  by陈 臻其实如果不是学习成本问题的话,erlang在这方面做的事情真的很多年了。

  byZoom Quieterl 的问题不是在文中指出的,而是配合现有工具/成员的问题,,,

  byBo Zhao所有的这些都可以在java或者C#中轻易的实现,请问node.js有什么可以超越上述两种语言的么?

  byLantao Liunode.js是个好东西,但是这里面提到的一些特性其实在大部分语言的主流框架中都已经实现了。使用javascript在服务器端编码,可以替换掉各种框架中的视图功能(MVC中的V功能 ),在程序中强制分离出渲染的逻辑。

  bypeng wang对node.js的优势感觉是没写清楚,至少我的理解不限如此。阻塞有好多得处理方法,并不是后端程序对阻塞没有好的解决办法。回调也很简单啊 Node公开宣称的目标是“旨在提供一种简单的构建可伸缩网络程序的方法”。就现阶段node的发展来看,实际更趋向于解决高并发、小逻辑并能提供独立服务的程序。

  我的机子上测试了一下,打开debugger后,如果str没有在闭包里被用到的话,闭包没有建立一个对str的引用记数,所以str在debuuger里是看不到的,自动被垃圾回收了。

  byyin michaelnode.js确实好,但是异步编程不一定能带来性能提升,同步api(或者作者所说的“阻塞编程”)实质上并没有真正阻塞,每一个线程在操作系统里可以为等待事件型号量而sleep。

  byqi elfErlang 也是很标准的函数语言啊,怎么不擅长计算了?Node相比而言还是会JavaScript的人更多

  bypc W这里的同步阻塞并不是因为忙等待而导致性能差。关键在于同步阻塞就不得不开多线程来处理并发。开线程是要消耗资源的。一般服务器也就能开数千线程。这时候线程切换的消耗占的比例就高的不可接受了。这才是同步阻塞的弊病

相关阅读