mongodb 异步io的问题
发布于 10 年前 作者 whzhyh 5592 次浏览 最后一次编辑是 8 年前

刚开始学,很多原理的东西不是很了解,请大家帮帮忙。

如下代码:

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应该是在不同的线程里执行的,应该可以正常插入。

请大家帮忙释疑。 谢谢。

13 回复

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

学习到新姿势了…

感谢,讲的很详细

回到顶部