Javascript 如何正确地允许NodeJ有机会在我的inifinite while循环中运行其异步事件

Javascript 如何正确地允许NodeJ有机会在我的inifinite while循环中运行其异步事件,javascript,mysql,node.js,events,Javascript,Mysql,Node.js,Events,每当我在位置B运行“save_to_db”函数时,它都会失败 下面的代码显示了问题 //location A var i = 0; while(true) { i++; if(i == 100) { //location B save_to_db(newUnit, 11214.1, 'TEST'); } } //location C “保存到数据库”功能在位置A和C处工作正常,但在位置B处失败 我认为这是因为while循环是无限的

每当我在位置B运行“save_to_db”函数时,它都会失败

下面的代码显示了问题


//location A

var i = 0;
while(true)
{

    i++;
    if(i == 100)
    {

//location B

        save_to_db(newUnit, 11214.1, 'TEST');
    }

}


//location C
“保存到数据库”功能在位置A和C处工作正常,但在位置B处失败

我认为这是因为while循环是无限的和同步的。因此,它不会给nodejs运行其事件循环的机会。在这种情况下,我们如何正确地给nodejs一个运行其事件循环的机会

===========================更新===============================

上面的代码是非常简单的代码版本。我有一个名为“db_util”的类/模块,它有两个方法,“save_to_db”和“read_from_db”。我认为,由于这些方法使用了“mysql”模块,所以它们以异步方式访问数据库。但是我的while-true循环会阻止nodejs-eventloop。因此while循环中的两个方法都没有机会被调用

var mysql = require('mysql');
var db_util = function()
{}

db_util.prototype = {
    save_to_db: function (neural_network, fitness, type) {
        var connection = mysql.createConnection({
            host: 'localhost',
            user: 'root',
            password: '',
            database: 'nodejstestdb'
        });
        connection.connect();      
        var addSql = 'INSERT INTO mytable(id, nn, type, fitness) VALUES(?,?,?,?)';
        var addSqlParams = [null, neural_network, type, fitness];
        connection.query(addSql, addSqlParams, function (err, result) {
            if (err) {
                console.log('[INSERT ERROR] - ', err.message);
                return;
            }                  
            console.log('INSERT ID:', result);          
        });
        connection.end();
    },


    read_from_db:function(){

        var connection = mysql.createConnection({
            host: 'localhost',
            user: 'root',
            password: '',
            database: 'nodejstestdb'
        });
        connection.connect();

        var sql = 'SELECT * FROM mytable ORDER BY fitness DESC'; 
        connection.query(sql, function (err, result) {
            if (err) {
                console.log('[SELECT ERROR] - ', err.message);
                return;
            }
            console.log(result);
            var nn = result[0].nn;            
            neural_network = synaptic.Network.fromJSON(JSON.parse(nn));           
            return neural_network;
        });
        connection.end();
    }
}

module.exports = db_util;


=====================由于答案而更新2

let i = 0;
(function tick() {
    ++i;
    if (i%100 == 0) {
        save_to_db();
    }
    setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}());
let i = 0;
tick();
@T.J.Crowder先生谢谢你的回答。但是上面的代码和下面的代码有什么区别呢

var i = 0;

function tick() {
    ++i;
    if (i%100 == 0) {
        save_to_db();
    }
    setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}

tick();
,我想知道为什么需要一个无限循环,而不仅仅是使用事件循环

我认为这是因为while循环是无限的和同步的。因此,它不会给nodejs运行其事件循环的机会

是的,你完全正确

如果不知道save_to_db是如何工作的,很难回答这个问题,但通常有三种选择:

使用一系列链接的setTimeout或setImmediate回调

变体:您执行一个块的工作,比如说,最多100次迭代,然后使用setTimeout来安排下一个块。 使用异步函数并等待save_to_db是否返回承诺,或者是否可以修改以返回承诺

使用a,当它应该执行save_to_db时,它会向主线程发布一条消息,那么被阻止的工作线程的事件循环不会阻止save_to_db所需的主线程上的事件。我可能不会为此雇用工人

1大致如下:

let i = 0;
(function tick() {
    ++i;
    if (i == 100) {
        save_to_db();
    }
    setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}());
(async () => {
    try {
        let i = 0;
        while (true) {
            if (i == 100) {
                await save_to_db();
            }
        }
    } catch (e) {
        // Handle/report error
    }
})();
请注意,Node.js rate限制计时器,因此setTimeouttick,0不一定会在下一个事件循环迭代中安排下一个调用。您可以使用,因为它

计划在I/O事件回调后立即执行回调

例如,此代码:

let i = 0;
let last = Date.now();
let sum = 0;
(function tick() {
    ++i;
    sum += Date.now() - last;
    if (i < 1000) {
        last = Date.now();
        setTimeout(tick, 0);
    } else {
        console.log(`Average: ${sum / i}`);
    }
})();
这样做的话,它在主线程上做了大量的工作,然后允许处理任何可能需要将_保存到_db的I/O回调,然后继续进行。您可以对它进行一点优化,只有当它知道save_to_db仍有工作要做时才返回,但这可能是过度工程了

2大致如下所示:

let i = 0;
(function tick() {
    ++i;
    if (i == 100) {
        save_to_db();
    }
    setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}());
(async () => {
    try {
        let i = 0;
        while (true) {
            if (i == 100) {
                await save_to_db();
            }
        }
    } catch (e) {
        // Handle/report error
    }
})();

3我将留给读者作为练习,但我可能不会为此使用worker。

运行事件,无限循环。选择一个。它们通常是不相容的。您不应该需要无限循环。当它中断循环时,请尝试使用setInterval而不是无限循环loop@VLAZ我明白这一点。如何将无限循环转换为“基于事件的结构”,有什么典型的例子吗?我想我发表了这篇评论,但证据表明并非如此save_to_db做什么?它是否回报了承诺?你是不止一次地调用它,还是仅仅当i==100时调用它?如果你不止一次地打电话,如果这些电话重叠会有问题吗?循环的目的是什么?我同意很难说OP想要做什么。他们似乎想向数据库中添加100项。也许是顺序的。也有可能save_to_db.then=>save_to_db.then save_to_db/*etc*/会起作用,或者可以使其起作用。或者可能有某种批量插入方法,或者可以很容易地创建一种:save_all_to_db@T.J.Crowder谢谢你的回答。我更新了问题。请参阅原始帖子。@wildcolor-我在1的实现中有一个编辑错误,请参阅更新。更新后,我的代码与您询问的其他代码之间的唯一区别是,勾号被添加到您的代码中出现的范围中,而不是我的代码中,因为命名函数表达式不会将函数名添加到它出现的范围中,只是在函数中。差别不大。@T.J.Crowder谢谢你的回答。我想这就是让我感到困惑的原因。也许这就是JS之所以快速的原因,因为这些“本机特性”。精彩的回答。然而,我确实注意到while循环和您的1答案之间存在着显著的性能差异。假设1中的“save_to_db”是一个console.logi。然后我注意到,与whiletrue{console.logi;}和settimeout 1方法相比,whiletrue要快得多。有什么评论吗?假设我们每10个数字打印一次,即使用i%10==0而不是i==100@wildcolor-是的,存在巨大的性能差异,因为在每次迭代中退回到事件循环会带来大量开销。此外,Node.js甚至可能不会在下一个事件循环上安排计时器回调 我提到的原因,也提到了分块/批量做事;它限制了计时器的速率。