Node.js带有多个get请求的意外堆栈溢出

时间:2014-03-22 10:18:39

标签: javascript node.js stack-overflow

我有一个从远程服务器或磁盘上的本地缓存获取JSON对象的函数。

在用例中,我必须使用不同的参数调用此函数几千次,但是当我这样做时,我得到最大堆栈溢出错误。我必须在某个地方进行递归调用,但我无法看到它的位置,因为我的process.nextTick函数调用似乎在正确的位置。

我在控制台中没有得到任何log.error读数,如果进行了任何重试请求的递归调用,这将是显而易见的。

控制台输出显示

重复出现
  

(节点)警告:检测到递归process.nextTick。这将在下一版本的节点中中断。请使用setImmediate进行递归递延。

...然后

  

RangeError:超出最大调用堆栈大小

然后程序退出。

任何人都可以就我可能做错的事情提供任何帮助吗?我完全难过了。

下面是调用有问题函数的函数" tf2inv.loadInventory()"

function refreshInventories(accounts, force, callback) {    
    //job executes download function, then pushes to inventories object
    var inventories = {};
    var Qinv = async.queue(function (task, invCallback) {
        tf2inv.loadInventory(
            task.force,
            task.steamid,
            function(inv, alias) {
                inventories[alias] = inv;
                process.nextTick(invCallback);
            }
        );
    }, 100)

    //when all queue jobs have finished, callback with populated inventories object
    Qinv.drain = function (err) {
        log.info('All inventories downloaded');
        callback(inventories);
    }

    //adding jobs to the queue
    for (var i = accounts.length - 1; i >= 0; i--) {
        Qinv.push({
            force: force,
            steamid: accounts[i]
        });
    };
}

此处显示的是从缓存中解析的函数,或来自远程服务器的请求。

//tf2inv
var loadInventory = function(force, sid, callback) {
    var invLoc = invFolder+sid
    if(force) { 
        if(fs.existsSync(invLoc)) {
            fs.unlinkSync(invLoc);
        }
    }

    if(fs.existsSync(invLoc)) {
        var body = fs.readFileSync(invLoc);
        try {
            var inventory = JSON.parse(body);
        } catch (e) {
            fs.unlinkSync(invLoc);
            log.error("parsing " + sid+"'s inventory");
            loadInventory(true, sid, invFolder, callback);  
            return;
        }
        process.nextTick(function() { callback(inventory, sid) })
        return;
    } else {
        var urlPre = "http://api.steampowered.com/IEconItems_440/GetPlayerItems/v0001/?key=";
        var urlSidPre = "&steamid=";
        var urlInvSuf = "&inventory=yes";
        var URL = urlPre+steam_API+urlSidPre+sid+urlInvSuf;
        http.get(URL, function (res) {
            var body = '';
            res.on('data', function (data) {
                body+=data; 
                fs.appendFile(invLoc, data);
            });
            res.on('end', function() {
                try {
                    inventory = JSON.parse(body);
                } catch (e) {
                    if(fs.existsSync(invLoc)) {
                        fs.unlinkSync(invLoc);
                    }
                    log.error("parsing " + sid+"'s downloaded inventory");
                    loadInventory(force, sid, invFolder, callback)
                    return;
                }
                process.nextTick(function() { callback(inventory, sid) })
                return;
            });
            res.on('error', function (e, socket) {
                log.error(sid + " inventory error")
                if(fs.existsSync(invLoc)) {
                    fs.unlinkSync(invLoc);
                }
                log.debug('Retrying inventory') 
                loadInventory(force, sid, invFolder, callback);
                return;
            })
            res.on('close', function () {res.emit('end'); log.error('connection closed')})
        })
        .on('error', function(e) {
            log.error(JSON.stringify(e));
            if(fs.existsSync(invLoc)) {
                fs.unlinkSync(invLoc);
            }
            log.debug('Retrying inventory') 
            loadInventory(force, sid, invFolder, callback)
            return;
        })
    }
};

1 个答案:

答案 0 :(得分:0)

很可能无法解析从服务器返回的正文。然后它立即再次调用自身,再次失败,无限循环并导致堆栈溢出。

我建议您不要在失败的解析时自动重试 - 如果失败一次,它可能会再次失败。最好回调一下错误,让你的编程部分调用它来处理错误,或者将它传回给可以让用户知道出错的地方。