nodejs/javascript中的嵌套函数

nodejs/javascript中的嵌套函数,javascript,node.js,Javascript,Node.js,据我所知,在javascript中嵌套函数会导致额外的声明/破坏,这可以通过使用“静态函数”甚至单例实现来避免。同样,“new”也做同样的事情,函数或对象的两个实例也是独立的副本 这是真的吗?如果是这样的话,我该怎么做才能拥有与嵌套函数和“new”相同的功能。这是一个服务器位于nodejs/javascript中的游戏。我已经达到了嵌套函数的8个级别,我开始担心了 例如: DB.cityUpdateUpkeep = function( cuid ) { /** @type {Array} */

据我所知,在javascript中嵌套函数会导致额外的声明/破坏,这可以通过使用“静态函数”甚至单例实现来避免。同样,“new”也做同样的事情,函数或对象的两个实例也是独立的副本

这是真的吗?如果是这样的话,我该怎么做才能拥有与嵌套函数和“new”相同的功能。这是一个服务器位于nodejs/javascript中的游戏。我已经达到了嵌套函数的8个级别,我开始担心了

例如:

DB.cityUpdateUpkeep = function( cuid )
{
/**  @type {Array} */
var buildings = null;

DB.cityGet( cuid, function( error, city )
{
    if( error )
    {
        console.log( "Couldn't get city" );
    }
    else
    {
        DB.iBuildings.find( {cuid:cuid}, function( error, cursor )
        {
            if( error )
            {
                console.log( "-error:" );
                console.log( error );
            }
            else
            {
                cursor.toArray( function( error, response )
                {
                    if( error )
                    {
                        console.log( "-error:" );
                        console.log( error );
                    }
                    else
                    {
                        console.log( "-the response:" );
                        console.log( response );
                        buildings = response;

                        var income  = city.resources.income;
                        var storage = city.resources.storage;
                        var stored  = city.resources.stored;

                        for( var buildingID in buildings )
                        {
                            var building = buildings[ buildingID ];
                            var blueprint = DB.bBuildings[ building.buid ];

                            if( blueprint.resources.income )
                            {
                                income = Utils.sumObjects( income, blueprint.resources.income );
                            }

                            if( blueprint.resources.storage )
                            {
                                storage = Utils.sumObjects( storage, blueprint.resources.storage );
                            }

                            if( blueprint.resources.stored )
                            {
                                stored = Utils.sumObjects( stored, blueprint.resources.stored );
                            }
                        }

                        console.log( "cuid: " + city._id + " income: " + income + " storage " + storage + " stored " + stored );
                    }
                });
            }
        });
    }
});
};

一种解决方案是存储函数,而不是匿名回调。它也更容易重用它们

DB.cityUpdateUpkeep = function (cuid) {
    var findHandler = function () { ... };

    DB.cityGet(cuid, function (error, city) {
        ...
        DB.iBuildings.find({cuid:cuid}, findHandler);
        ...
    });
};

我建议您选择一个控制流库(异步是最流行的一个),而不是一堆回调,您可以选择
瀑布式

async.parallel([
    function(callback){
        setTimeout(function(){
            callback(null, 'one');
        }, 200);
    },
    function(callback){
        setTimeout(function(){
            callback(null, 'two');
        }, 100);
    }
],
// optional callback
function(err, results){
    // the results array will equal ['one','two'] even though
    // the second function had a shorter timeout.
});
(代码借用自async的主网站)。因此,如果要在这些嵌套函数之间共享变量,可以在顶级的DB.cityUpdateUpkeep中定义它,其他嵌套函数也可以使用它。但是,请注意,如果您随时修改该变量,则稍后运行的函数将受到影响

这些嵌套函数有多糟糕?没什么,这是nodejs的本质(异步编程模型),你必须接受它。为了便于维护,您必须重新安排代码,不过请看一下平坦回调的方法(代码会更好一些)。对于您的特定示例,我更喜欢使用多种方法进行重构:

  • 在出错时尽早返回方法(使您不必嵌套其他方法)
  • 在异步调用不依赖时并发执行它们(注意DB.cityGet和DB.iBuildings.find-使代码运行得更快)
  • 在嵌套外部创建函数和引用(例如checkComplete)
  • 我的重构如下:

      DB.cityUpdateUpkeep = function( cuid ){
        /**  @type {Array} */
        var buildings = null;
        var city = null;
        var checkComplete = function(){
            if (!city || !builings){
                return;
            }   
            var income  = city.resources.income;
            var storage = city.resources.storage;
            var stored  = city.resources.stored;
    
            for( var buildingID in buildings ){
                var building = buildings[ buildingID ];
                var blueprint = DB.bBuildings[ building.buid ];
    
                if( blueprint.resources.income ){
                    income = Utils.sumObjects( income, blueprint.resources.income );
                }   
    
                if( blueprint.resources.storage ){
                    storage = Utils.sumObjects( storage, blueprint.resources.storage );
                }   
    
                if( blueprint.resources.stored ){
                    stored = Utils.sumObjects( stored, blueprint.resources.stored );
                }   
            }   
    
            console.log( "cuid: " + city._id + " income: " + income + " storage " + storage + " stored " + stored );
    
        }   
        DB.cityGet(cuid, function(err, response){
            if (err){
                console.log("Couldn't get city");
                return;
            }   
            city = response;
            checkComplete();
        }); 
        DB.iBuildings.find({cuid:cuid}, function(err, cursor){
            if (err){
                console.log(err);
                return;
            }   
            cursor.toArray(function(err, response){
                if (err){
                    console.log(err)
                    return;
                }   
                buildings = response;
                checkComplete(); 
            }); 
        }); 
    });
    

    你是如何筑巢的?这些是什么功能?8级?认真地听起来像是回调而不是嵌套函数。你能举个例子吗?现在的问题太笼统了,可以通过向您介绍有关命名函数、使用承诺、使用事件等的文章来解决。。。注意我是如何从顶层到底层使用“城市”的。我将不得不对所有这些函数进行大量参数化,这可能会使事情变得过于复杂。只是考虑我在顶层添加一个参数,我需要在底部;我必须在整个链中传递该值:|不管怎样,这些嵌套函数到底有多糟糕?它确实看起来更好。每次调用cityUpdateUpkeep时,仍然会创建checkComplete和处理程序。不过,对于并行调用,+1。我很难弄清楚范围,但现在我明白了,我觉得它是多么的简单:)哎呀,关于检查完成,你是对的。只需将其移出函数即可。处理程序应该在现代javascript引擎中得到清理。事实上,据我所知,checkComplete也不会每次都重新分配-但最好是安全的。