刚开始学,很多原理的东西不是很了解,请大家帮帮忙。
如下代码:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var counter = 1;
var Cat = mongoose.model('Cat', {
name: String
});
var kitty = new Cat({
name: 'Zildjian'
});
for (i = 1; i < 1000; i++) {
console.log("loop start");
kitty.save(function(err) {
console.log("saved " + counter++);
if (err) // ...
console.log('meow');
});
console.log("loop end");
}
在我的预期中,循环在跑的过程中会有数据插入到数据库,但是事实并非如此。要等到循环结束,才开始有数据插入。我觉着即使循环是一个cpu密集操作,有可能会阻塞回调函数的执行,但是数据库io应该是在不同的线程里执行的,应该可以正常插入。
请大家帮忙释疑。 谢谢。
js 常见问题… 你for 循环有异步的话…得用闭包写法…
@thesadboy这个问题我考虑过了,也试过,把for循环从1000增大到100000,直到内存超过1.4G而崩溃,也插入不了一条
这个不太理解,能说的详细点,谢谢
@whzhyh 这个是js 入门知识吧…
类似这种 , 回去认真学习一下闭包…
(function (i){
console.log('index ->' + i);
kitty.save(function(err) {
console.log("saved " + counter++);
if (err) // ...
console.log('meow');
});
})(i);
@youxiachai经过测试,跟我的那个效果是一样的。这里的困惑是这样子的,因为save()本来就应该是个异步的方法,所以这个用不用这种闭包写法似乎没有区别。
@thesadboy 100000级别的循环没有到那么快,不会马上完成。。不过按你的说法我加了sleep, 在npm里找了个sleep模块,之后采用类似如下代码,不过依然没有插入。
var sleep = require('sleep');
for (var i = 1; i < 1000000; i++) {
console.log("loop start " + i);
kitty.save(function(err) {
console.log("saved " + counter++);
if (err) // ...
console.log('meow');
});
console.log("loop end");
sleep.sleep(1)//sleep for 1 seconds
}
真是奇了怪了。会不会是mongoose的问题, 想用native driver试下。
改成这样就好了:
for(var i=0; i<10; i++) {
// or process.nextTick
setImmediate(function() {
console.log('loop start');
kitty.save(function(err) {
if(!err) console.log('saved!');
else console.log('save err~');
});
console.log('loop end!');
});
}
去了解下事件循环吧~
谢谢回复。那为什么如下代码不能按预期工作呢.我想知道到底是for循环执行完才save,还是在for循环运行中就异步的执行了save, 但是插入了console.log之后似乎没有按预期运行,谢谢
for (var i = 0; i < 10000; i++) {
// or process.nextTick
console.log('loop start');
setImmediate(function() {
kitty.save(function(err) {
if (!err) console.log('saved!');
else console.log('save err~');
});
});
console.log('loop end!');
}
@whzhyh 加了setImmediate,for循环里在当此事件循环里就不在执行save,会把save放到下一次事件循环的开头,所以你这样看到的将是一堆的console.log之后才是save
因个人认为,用for不管怎么改都得等这个循环完成之后才能保存成功,因为那个save里面应该有一个process.nextTick
异步是当加载进程的时候,调用IO操作时,解释器会通知事件循环将事件和处理程序注入到事件队列中,等待下一个事件循环在调用,此时解释器会绕过异步操作直接执行下面的流程,一般情况下,下一个事件循环调用的时间是在当前作用域没有待执行的任务,才触发下一个事件循环
所以在循环100000次的时候,在循环中有个异步方法,这个异步方法会等待当前事件循环处理完任务后,在调用,所以看到的就是先console.log后save
学习到新姿势了…
感谢,讲的很详细