Node.js expressjs在完成之前一直挂在重载函数上

Node.js expressjs在完成之前一直挂在重载函数上,node.js,mongodb,express,mongoose,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.kar

我有一个循环函数,我正在为我的一条路径测试它。问题是,当我调用它时,它会挂起所有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');
        }
    }
};
app.get('/populate',routes.populate);
exports.populate=函数(req、res、next){
对于(i=0;i<100000;i++){
var tmp=新遭遇();
tmp.karoid='1234';//mock.Address.zipCode();
tmp.patient.fullName='Vartan Arabyan';//mock.Name.findName();
tmp.patient.dob=Date.now();
tmp.patient.karoid='12312';//mock.Address.zipCode();
tmp.medicine.fullName=“Dr.”+‘Vartan Arabyan’;//mock.Name.findName();
tmp.medicine.karoid='12312';//mock.Address.zipCode();
tmp.appointmentType=“NCV Upper”;
tmp.appointment=Date.now();
tmp.save(功能(错误){
如果(错误)抛出错误;
});
如果(i==99999){
res.send(200,“加载假数据”);
}
}
};

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

此循环会阻止事件循环,直到它迭代100000次。请尝试以下方法:

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/:counter路由发送100000个请求。您可以使用节点的另一个实例创建假请求,您可以执行以下操作:

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();  
};
var http=require('http');
变量选项={
主机名:“localhost”,
端口:3000,//我假设您的express在端口3000上运行。。。
方法:“获取”
};
var-req;
对于(变量i=0;i<100000;i++){
options.path='/populate/'+i;
req=http.request(选项、函数(res){
res.setEncoding('utf8');
如果(res.statusCode==400){
//处理“加载的假数据”
console.log('加载了假数据..');
}
其他的
console.log('仍不存在!发送更多数据…')
res.on('数据'),函数(数据){
控制台日志(数据);
});
});
请求开启('错误',功能(e){
log('请求问题:'+e.message);
});
请求结束();
};

您必须注意,在发出100000个http请求时,另一个节点实例将被阻止。但您的express实例在处理这些请求时不会被阻止…

将其重写为非阻止状态并使用回调

也就是说,有很多小的快速功能,而不是一个大的慢速功能

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

它“挂起”的原因是node.js是单线程的。我建议阅读node.js、回调以及如何编写非阻塞

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

使用软件包
.parallel()
.series()
-文档和大量示例。如果执行顺序很重要,请使用series(),如果不重要,请使用parallel()

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

:


尝试增加保存中的计数器(仅当
save
成功返回时,才创建下一个
遭遇
实例)。事实上,你的代码创建了10000个对象,并将10000个保存排队。你能给我一个建议的例子吗?这是一个很大的http协议开销-为什么不直接使用循环和闭包进行异步路径呢?这几乎是一样的,使用
async.times
只会稍微缓解一点问题。这里的问题是循环的大小(100K),即使使用
async.times
也很容易使事件循环停止(:在我的测试中,超时时间几乎是预期的3倍)对数据库执行任何操作100K次,这将需要一些时间:)从内存中,
.times()
是串行的-您可以在
.parallel()中运行100倍,以获得潜在的速度boostIf如果任务是向数据库注入丢弃的数据,为什么不直接在数据库上运行脚本呢?模型是否做了任何不能用db“restore”脚本模拟的自定义操作?在循环的每次迭代(或两次迭代)后,也可以使用
setImmediate
,这将产生事件循环。然而,这将大大降低100K循环的速度。
// 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
});