use*_*ser 4 javascript node.js
嗨,我正在使用Node.js和Fulephp进行一些测试.我有一个简单的设置,我试图看看什么更快.我在mogodb中有1万条记录被录入视图.设置很简单,没有js,没有css,只有最小的html.我很快注意到php的设置速度是原来的两倍.起初我认为nodejs比较慢,并继续我的生活.然而,我决定尝试没有玉的节点,我用它作为我的模板引擎,幸运的是,我遇到了一个关于stackoverflow的帖子,玉背后的哲学不是速度而是优雅.然后我决定尝试没有任何温度的节点.引擎.但是我很快就遇到了问题,因为我意识到我不知道如何将数据从数据库和节点传递到客户端.我在一个漫长的恐怖和绝望的夜晚.在某些时候,我得出结论,我需要socket.io的帮助.虽然我能够连接到socket.io最终我仍然无法弄清楚如何传递数据.然后我决定回去使用临时工.引擎,但这次我决定尝试ejs.最终我能够渲染一些具有以下形式[object object]的数据,但它不是一万条记录,更像是25条.我决定做正确的事情并在这里发布我的问题.我想在没有模板引擎的情况下渲染视图,看看我的假设是否正确.毕竟我正在尝试做两件事,了解如何将数据传递到客户端表单node.js,看看它是否会提高我的性能.
这是我的app.js,有一些评论:
/**
* Mongo DB
*/
var mongous = require('mongous').Mongous,
dbCollection = 'test.personnel';
/**
* Module dependencies.
*/
var express = require('express'),
app = module.exports = express.createServer(),
pub = __dirname + '/public';
// Configuration
app.configure(function(){
app.set('view options', {layout: false});
//not sure if i need these here, but left it in case
app.use(app.router);
app.use(express.static(pub));
});
//Simple templating
//I took this example from stackoverflow,
//can't find that post anymore,
//though I can look if need be
app.register('.html', {
compile: function(str, options){
return function(locals){
return str;
}
}
});
// Routes
//This is where data is right now, it need to end up on the client side
//This was working with jade and kinda worked with ejs (though I am not sure because I was getting [object Object])
//--------------------------------------------------
app.get('/', function(req, res){
mongous(dbCollection).find(function(output){
res.render('index.html',{
//the data is here, it works, i tested it with console.log
data: output.documents
});
});
});
//--------------------------------------------------
app.configure('production', function(){
app.use(express.errorHandler());
});
app.listen(3000);
console.log('Express server listening on port %d in %s mode', app.address().port, app.settings.env);
Run Code Online (Sandbox Code Playgroud)
这是我的观点:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Index</title>
</head>
<body>
<div id="data">
Data needs to end up here. Somehow...
</div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
你在那里看不到多少.现在我明白我很可能需要在客户端使用某种模板引擎,一旦我在客户端获得数据,我就能自己解决.最后可能更慢,但我的主要目标是了解如何将node.js中的数据传递给客户端,以便我可以继续进行实验.请尽可能帮助,这将显着提高我对节点的理解.谢谢.
编辑: 在你们所有人的帮助下,尤其是josh3736,如果你有兴趣的话,这就是我最终的结果...... http://pastie.org/private/z3fjjbjff8284pr2mafw
正如你在答案中提到的,部分问题是模板引擎本身的速度; 你发现玉不是最快的 - 事实上,它是最慢的之一.
我最喜欢的引擎是doT.在我链接的性能测试中,doT可以每秒渲染模板540 万次.Jade每秒只能渲染29,000次类似的模板.这甚至不是一场比赛.
然而,模板引擎速度只是这里问题的一小部分.我相信你真正的问题是你正在使用的Mongo驱动程序似乎设计不好用于Node的异步模型. (免责声明:我从未真正使用Mongous;我只花了几分钟查看代码.)
节点旨在处理数据流.换句话说,您应该一次在非常小的数据块上运行.相比之下,看起来像Mongous处理整个数据集并将其作为一个JSON对象返回到您的代码.
这对于小型数据集来说非常方便,但是在处理大量数据(10,000条记录)时会完全崩溃.在解析和处理那么多数据时,节点将被完全锁定(这非常非常糟糕,因为它无法处理任何传入连接),并且V8内存管理系统没有针对大堆分配进行优化.
要正确使用大型数据集,您必须使用Mongo驱动程序将记录流式传输到您的代码,例如node-mongodb-native或mongoskin,这使得API更容易处理.
maerics的回答是在正确的轨道上,但是因为它使用了错误toArray,这会产生与Mongous相同的问题:整个数据集被整理成内存数组.所以,应该使用游标的each方法,该方法调用异步回调函数对每个返回的记录,因为它进来.这样,整个结果集永远不会在内存中; 您只能一次使用一个,允许丢弃您已处理的记录并在必要时收集垃圾.
现在我们已经建立了如何从数据库中获取数据的方法,我们需要弄清楚如何将数据传输到客户端.
这里的问题是Express的视图系统要求您预先提供所有数据,以便模板引擎可以呈现出要发送给客户端的单个字符串.正如我们上面所讨论的,如果您处理数千条记录,这不是一个好主意.正确的方法是将我们从Mongo直接获取的数据流式传输到客户端.不幸的是,我们无法在Express视图中真正做到这一点 - 它们并非设计为异步.
相反,您将不得不编写自定义处理程序.你已经走上了Hippo的答案和你自己的尝试,但你真正需要使用的是res.write(),而不是res.send.像res.render,res.send希望你有当你调用它,因为它在内部调用一个完整的响应res.end,结束了HTTP响应.相比之下,res.write只需通过网络发送数据,打开HTTP响应并准备发送更多数据 - 换句话说,流式传输您的响应.(请记住,在开始流式传输之前必须设置任何HTTP标头.例如,res.contentType('text/html');)
仅仅因为您手动处理响应(在视图渲染系统之前)并不妨碍您利用模板引擎.您可以使用模板作为文档的页眉和页脚,每个记录使用一个模板.让我们用doT把所有东西放在一起.
首先,让我们声明我们的模板.在现实生活中,你可能会从文件加载这些(甚至破解快速加载它们对你的看法,并获得模板源),但我们只是宣布他们在我们的代码.
var header = doT.template('<!DOCTYPE html><html><head><title>{{=it.title}}</title></head><body>');
var record = doT.template('<p>{{=it.fieldname}}, ...</p>');
var footer = doT.template('</body></html>');
Run Code Online (Sandbox Code Playgroud)
(doT.template返回一个从我们上面给出的模板生成HTML的函数,以及在调用它时传递给返回函数的对象.例如,现在我们可以调用header({title:'Test'});)
现在我们在请求处理程序中执行实际工作:(假设我们已经有一个collection来自Mongo驱动程序)
app.get('/', function(req, res){
res.contentType('text/html');
res.write(header({title:'Test'}));
collection.find({}).each(function(err, doc) {
if (err) return res.end('error! ' + err); // bail if there's an error
if (doc) {
res.write(record(doc));
} else { // `doc` will be null if we've reached the end of the resultset.
res.end(footer());
}
});
});
Run Code Online (Sandbox Code Playgroud)