Express js挂起功能很重,直到完成

时间:2013-05-28 22:06:43

标签: node.js mongodb express mongoose

我有一个循环功能,我正在测试我的一条路线。问题是,当我调用它时,挂起所有Web调用,直到完成该功能。我想知道在处理节点时如何不锁定节点。

app.get('/populate', routes.populate);

exports.populate = function(req, res, next){

    for(i = 0; i < 100000; i++){
        var tmp = new Encounters();

        tmp.kareoId = '1234'; //mock.Address.zipCode();

        tmp.patient.fullName = 'Vartan Arabyan'; //mock.Name.findName();
        tmp.patient.dob = Date.now();
        tmp.patient.kareoId = '12312'; //mock.Address.zipCode();

        tmp.physician.fullName = "Dr." + 'Vartan Arabyan'; //mock.Name.findName();
        tmp.physician.kareoId = '12312'; //mock.Address.zipCode();

        tmp.appointmentType = "NCV Upper";
        tmp.appointment = Date.now();

        tmp.save(function(err){
            if (err) throw err;
        });

        if(i == 99999){
            res.send(200, 'Fake Data Loaded');
        }
    }
};

3 个答案:

答案 0 :(得分:0)

你需要在回调中调用你的tmp变量设置。 App.VERB()是非阻塞的。我不熟悉mongoose,但是所有带有tmp变量的代码似乎都是阻塞的。没有回调,所以变量是逐个设置的,当你写这几千次时变得明显。

答案 1 :(得分:0)

此循环阻止事件循环,直到迭代100,000次。试试这个:

app.get('/populate/:counter', routes.populate);

exports.populate = function(req, res, next){

     var tmp = new Encounters();

     tmp.kareoId = '1234'; //mock.Address.zipCode();

     tmp.patient.fullName = 'Vartan Arabyan'; //mock.Name.findName();
     tmp.patient.dob = Date.now();
     tmp.patient.kareoId = '12312'; //mock.Address.zipCode();

     tmp.physician.fullName = "Dr." + 'Vartan Arabyan'; //mock.Name.findName();
     tmp.physician.kareoId = '12312'; //mock.Address.zipCode();
     tmp.appointmentType = "NCV Upper";
     tmp.appointment = Date.now();

     tmp.save(function(err){
         if (err) throw err;
     });

     if(req.param('counter') == 99999){
         return res.send(400, 'Fake Data Loaded');
     }
     res.send(200, 'Send me more Data');
};

然后,在循环中向/ populate /:计数器路由发送100,000个请求。您可以使用另一个节点实例来创建虚假请求,您可以执行以下操作:

var http = require('http');

var options = {
    hostname: 'localhost',
    port: 3000,  // I assumed that your express is running on port 3000...
    method: 'GET'
};

var req;
for (var i = 0; i < 100000; i++) {
    options.path = '/populate/' + i;
    req = http.request(options, function(res) {
        res.setEncoding('utf8');
        if (res.statusCode == 400) {
            // Handle 'Fake Data Loaded'
            console.log('Fake data loaded..');
        }
        else 
            console.log('Still not there yet! Send more data...') 
        res.on('data', function (data) {
            console.log(data);
        });
    });

    req.on('error', function(e) {
        console.log('problem with request: ' + e.message);
    });

    req.end();  
};

您必须注意,在发出100,000个http请求时,其他节点实例将被阻止。但处理这些请求时,您的快递实例不会被阻止......

答案 2 :(得分:0)

将其重写为非阻塞并使用回调

即。许多小的快速功能,而不是一个大的慢功能。

你应该尽量避免缓慢的繁重功能。把它分解成小任务。

它'挂起'的原因是因为node.js是单线程的。我建议阅读node.js Event Loop,回调以及如何编写非阻塞。

如果您有许多小功能,快递可以在第一个“仍在运行”时响应请求。可以将事件循环看作是按顺序执行的任务数组。

使用aysnc.parallel().series() - 文档和大量示例github repo。如果执行顺序很重要,则使用series();如果不执行,则使用parallel()。

在您的示例中,您希望快速插入100k行。 创建一个插入一行的函数,并在完成后调用next()回调函数。 创建一个运行res.send()的完成函数 使用async.times()执行创建功能,然后在完成运行完成功能时使用。

See async.times() documentation on their github repo

// Pretend this is some complicated async factory
var createUser = function(id, callback) {
  callback(null, {
    id: 'user' + id
  })
}
// generate 5 users
async.times(5, function(n, next){
    createUser(n, function(err, user) {
      next(err, user)
    })
}, function(err, users) {
  // we should now have 5 users
});