javascript - 将数据从数据库发送到客户端,而无需使用模板引擎(node.js)

标签 javascript node.js

嗨,我正在用Node.js和Fulephp进行一些测试。我做了一个简单的设置,然后尝试查看更快的方法。我在mogodb中有1万条记录被拉入 View 。设置很简单,没有js,没有CSS,并且HTML最少。我很快注意到php的设置速度是以前的两倍。起初,我认为nodejs速度较慢,并且一生都在继续前进。但是我决定尝试使用没有 Jade 的 Node 作为模板引擎,但碰巧的是,我碰到了stackoverflow上的一篇文章,指出 Jade 的原理不是速度而是优雅。然后,我决定尝试没有任何临时性的 Node 。引擎。但是自以来,我很快就遇到了一个问题,我意识到我不知道如何将数据从数据库和 Node 传递到客户端。我整夜都在恐惧和绝望中。在某个时候,我得出的结论是我需要socket.io的帮助。尽管最终我能够连接到socket.io,但仍然无法弄清楚如何传递数据。然后,我决定回去使用临时工。引擎,但是这次我决定尝试ejs。最终,我能够呈现某些格式为 [object Object] 的数据,但它不是1万条记录,更像是25条记录。我决定做对的事情并在此处提出我的问题。我想在不使用模板引擎的情况下呈现 View ,以查看我的假设是否正确。 毕竟,我试图做两件事,以了解如何将数据从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);

这是我的看法:
<!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>

如您所见,里面没有太多东西。现在,我了解到,我很可能将需要在客户端使用某种模板引擎,并且一旦在客户端获得了数据,我便可以自己进行工作。最终可能会更慢,但是我的主要目标是了解如何将node.js中的数据传递给客户端,以便我可以继续进行实验。 如果可以的话,请帮忙,它将大大提高我对node的理解。谢谢你。

编辑:
在大家的帮助下,尤其是 josh3736 ,如果您有兴趣,这就是我最终得到的...
http://pastie.org/private/z3fjjbjff8284pr2mafw

最佳答案

正如您在回答中所暗示的那样,部分问题在于模板引擎本身的速度。您发现Jade不是最快的-实际上是it's one of the slowest

我最喜欢的引擎是doT。在我链接到的performance test中,doT每秒可渲染模板5.4 百万次。 Jade每秒只能渲染29,000次类似的模板。这甚至不是比赛。

但是,在这里确定发动机转速只是问题的一小部分。我相信您真正的问题是您正在使用的Mongo驱动程序似乎不适用于Node的异步模型。 (免责声明:我从未真正使用过Mongous;我只花了几分钟查看代码。)

Node旨在处理数据流。换句话说,您应该一次处理非常小的数据块。相反,看起来Mongous处理了整个数据集并将其作为一个JSON对象返回到您的代码中。

这对于小型数据集来说很方便且很好,但是在像您一样处理大量数据(10,000条记录)时完全崩溃了。 Node 将在解析和处理那么多数据时被完全锁定(这非常非常糟糕,因为它无法处理任何传入的连接),并且V8内存管理系统并未针对此类大型堆分配进行优化。

为了正确处理大型数据集,您必须使用Mongo驱动程序,该驱动程序会将记录流式传输到您的代码中,例如node-mongodb-native或mongoskin,这使该API更加易于处理。

maerics的回答是正确的,但是是错误的,因为它使用了toArray,这产生了与Mongous相同的问题:整个数据集都整理到一个内存数组中。相反,只需使用游标的each方法,该方法就针对传入的每个返回记录异步调用您的回调函数。您一次只能处理一个记录,因此可以丢弃已经处理的记录,并在必要时进行垃圾收集。

现在,我们已经确定了如何从数据库中获取数据,我们需要弄清楚如何将其获取到客户端。

这里的问题是Express的 View 系统希望您可以预先获得所有数据,以便模板引擎可以呈现出单个字符串以发送给客户端。如上所述,如果您要处理成千上万的记录,那么这并不是一个好主意。正确的方法是将我们从Mongo获得的数据直接流式传输到客户端。不幸的是,我们无法在Express View 中真正做到这一点-它们并非设计为异步的。

相反,您将不得不编写一个自定义处理程序。您已经有了Hippo的答案和自己的尝试,但是您真正需要使用的是res.write(),而不是res.send。像res.render一样,res.send希望您在调用它时得到完整的响应,因为它在内部调用res.end,从而结束了HTTP响应。相比之下,res.write只是通过网络发送数据,使HTTP响应保持打开状态,并准备发送更多数据-换句话说,流式传输您的响应。 (请记住,开始流之前必须设置所有HTTP header 。例如res.contentType('text/html');)

仅仅因为您正在手动处理响应(在 View 渲染系统之前),并不妨碍您利用模板引擎。您可以将模板用于文档的页眉和页脚,并为每个记录使用一个模板。让我们使用doT将所有内容放在一起。

首先,让我们声明我们的模板。在现实生活中,您可能会从文件中加载这些文件(甚至是hack Express以将它们作为 View 加载并获取模板源),但是我们只是在代码中声明它们。

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>');

(doT.template返回一个函数,该函数根据上面提供的模板生成HTML,并在调用它时将一个对象传递给该返回的函数。例如,现在我们可以调用header({title:'Test'});)

现在,我们在请求处理程序中进行实际工作:(假设我们已经从Mongo驱动程序中获得了collection)
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());
        }
    });
});

关于javascript - 将数据从数据库发送到客户端,而无需使用模板引擎(node.js),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9153763/

相关文章:

android - Cordova 找不到模块

MysqlDump npm 显示 javascript 堆内存不足。适用于小于 1 gb 的 Mysql 文件。有人知道如何解决这个问题吗?

javascript - Sails.js 中非持久模型的最佳实践?

javascript - 使用 ng-repeat 在 Angular js 中填充表格

javascript - 为什么在下面的 Node js 程序中,S 函数中的第一个 for 循环会无限运行?

javascript - 图像类别根据一天中的时间而变化

javascript - 正则表达式,匹配除双星号之外的所有内容

javascript - Express.js 到 EJS 部分渲染数据

javascript - 在javascript中创建一个只有年份作为参数的日期对象

javascript - 如何更新对象内字符串中的 html 元素?