Node.js 应用跑得更快 10 个技巧
NodeJS是一个服务器端JavaScript解释器,它将改变服务器应该如何工作的概念。它的目标是帮助程序员构建高度可伸缩的应用程序,编写能够处理数万条同时连接到一个(只有一个)物理机的连接代码。
Node.js受益于它的事件驱动和异步的特征,已经很快了。但是,在现代网络中只是快是不行的。如果你打算用Node.js开发你的下一个Web应用的话,那么你就应该无所不用其极,让你的应用更快,异常的快。本文将介绍10条,经过检验得知可大大提高Node应用的技巧。废话不多说,让我们逐条来看看。
1.并行
创建Web应用的时候,你可能要多次调用内部API来获取各种数据。比如说,假设在Dashboard页面上,你要执行下面这几个调用:
用户信息-getUserProfile().
当前活动-getRecentActivity().
订阅内容-getSubscriptions().
通知内容-getNotifications().
为了拿到这些信息,你应该会为每个方法创建独立的中间件,然后将它们链接到Dashboard路由上。不过问题是,这些方法的执行是线性的,上一个没结束之前下一个不会开始。可行解决案是并行调用它们。
如你所知由于异步性,Node.js非常擅长并行调用多个方法。我们不能暴殄天物。我上面提到的那些方法没有依赖性,所以我们可以并行执行它们。这样我们可以削减中间件数量,大幅提高速度。
我们可以用async.js来处理并行,它是一个专门用来调教JavaScript异步的Node模块。下面代码演示怎样用async.js并行调用多个方法的:
functionrunInParallel(){ async.parallel([ getUserProfile, getRecentActivity, getSubscriptions, getNotifications ],function(err,results){ //Thiscallbackrunswhenallthefunctionscomplete }); }
如果你想更深入了解async.js,请移步它的GitHub页面。
2.异步
根据设计Node.js是单线程的。基于这点,同步代码会堵塞整个应用。比如说,多数的文件系统API都有它们的同步版本。下面代码演示了文件读取的同步和异步两种操作:
//Asynchronous fs.readFile('file.txt',function(err,buffer){ varcontent=buffer.toString(); }); //Synchronous varcontent=fs.readFileSync('file.txt').toString();
不过要是你执行那种长时间的阻塞操作,主线程就会被阻塞到这些操作完成为止。这大大降低你应用的性能。所以,最好确保你的代码里用的都是异步版本API,最起码你应该在性能节点异步。而且,你在选用第三方模块的时候也要很小心。因为当你想方设法把同步操作从你代码中剔除之后,一个外部库的同步调用会让你前功尽弃,降低你的应用性能
3.缓存
如果你用到一些不经常变化的数据,你应该把它们缓存起来,改善性能。比如说,下面的代码是获取最新帖子并显示的例子:
varrouter=express.Router(); router.route('/latestPosts').get(function(req,res){ Post.getLatest(function(err,posts){ if(err){ throwerr; } res.render('posts',{posts:posts}); }); });
如果你不经常发贴的话,你可以把帖子列表缓存起来,然后一段时间之后再把它们清理掉。比如,我们可以用Redis模块来达到这个目的。当然,你必须在你的服务器上装Redis。然后你可以用叫做node_redis的客户端来保存键/值对。下面的例子演示我们怎么缓存帖子:
varredis=require('redis'), client=redis.createClient(null,null,{detect_buffers:true}), router=express.Router(); router.route('/latestPosts').get(function(req,res){ client.get('posts',function(err,posts){ if(posts){ returnres.render('posts',{posts:JSON.parse(posts)}); } Post.getLatest(function(err,posts){ if(err){ throwerr; } client.set('posts',JSON.stringify(posts)); res.render('posts',{posts:posts}); }); }); });
看到了吧,我们首先检查Redis缓存,看看是否有帖子。如果有,我们从缓存中拿这些帖子列表。否则我们就检索数据库内容,然后把结果缓存。此外,一定时间之后,我们可以清理Redis缓存,这样就可以更新内容了。
4.gzip压缩
开启gzip压缩对你的Web应用会产生巨大影响。当一个gzip压缩浏览器请求某些资源的时候,服务器会在响应返回给浏览器之前进行压缩。如果你不用gzip压缩你的静态资源,浏览器拿到它们可能会花费更长时间。
在Express应用中,我们可以用内建express.static()中间件来处理静态内容。此外,还可以用compression中间件压缩和处理静态内容。下面是使用例:
varcompression=require('compression'); app.use(compression());//usecompression app.use(express.static(path.join(__dirname,'public')));
5.尽量在客户端渲染
现在有超多功能强劲的客户端MVC/MVVM框架,比如说AngularJS,Ember,Meteor,等等,构建一个单页面应用变得非常简单。基本上,你只要公开一个API,返回JSON响应给客户端就可以了,而不需要在服务端渲染页面。
在客户端,你可以用框架来组织JSON然后把它们显示在UI上。服务端只发送JSON响应可以节省带宽,改善性能,因为你不需要在每个响应里面都返回布局标记了,对吧,你只需要返回纯JSON,然后在客户端渲染它们。
6.不要在Session存储太多数据
典型的Express页面应用,Session数据默认是保存在内存中的。当你把太多数据保存在Session的时候,会导致服务器开销显著增大。所以,要么你切换到别的储存方式来保存Session数据,要么尽量减少存储在Session中的数据量。
比如说,当用户登录到你的应用的时候,你可以只在Session中保存他们的ID而不是整个用户数据对象。还有,对于那些你能够从id拿到对象的查询,你应该会喜欢用MongoDB或者Redis来存储session数据。
7.优化查询
假设你有个博客,你要在主页上显示最新帖子。你可能会通过Mongoose这样取数据:
Post.find().limit(10).exec(function(err,posts){ //sendpoststoclient });
不过问题是Mongoose的find()方法会把对象的所有字段都查询出来,而许多字段在主页上并不要求。比如说,commentsis保存的是特定帖子的回复。我们不需要显示文章回复,所以我们可以在查询的时候把它给剔除掉。这无疑会提高速度。可以像这样优化上面那条查询:
Post.find().limit(10).exclude('comments').exec(function(err,posts){ //sendpoststoclient });
8.用标准的V8方法
集合上的一些操作,比如map,reduce,和forEach不一定支持所有浏览器。我们可以通过前台的库解决部分浏览器兼容性问题。但对于Node.js,你要确切知道Google的V8JavaScript引擎支持哪些操作。这样,你就可以在服务端直接用这些内建方法来操作集合了。
9.在Node前面用Nginx
Nginx是个微小型轻量Web服务器,用它可以降低你的Node.js服务器的负载。你可以把静态资源配置到nginx上,而不是在Node上。你可以在nginx上用gzip压缩响应,让所有的响应都变得更小。所以,如果你有个正在营运的产品,我觉得你应该会想用nginx来改善运行速度的。
10.打包JavaScript
最后,你还可以大大提高页面应用速度,通过把多个JS文件打包。当浏览器在页面渲染中碰到<script\>元素的时候会被堵塞,直到拿到这个脚本才继续运行(除非设置了异步属性)。比如,如果你的页面有五个JavaScript文件,浏览器会发出五个独立的HTTP请求来获取他们。如果把这五个文件压缩打包成一个,整体性能将可以大幅提升。CSS文件也是一样。你可以用诸如Grunt/Gulp这样的编译工具来打包你的资源文件。
通过以上十个方面给大家介绍了Node.js应用跑得更快的技巧,希望对大家有所帮助!