node.js超时在长轮询中加起来

时间:2014-06-29 18:26:57

标签: javascript node.js long-polling

我正在使用以下内容进行基本的长轮询:

var http = require('http');
var url = require('url');
var Memcached = require('memcached');
var libAS = require('./libAS');
var cache = new Memcached('localhost:11211');

http.createServer(function(request,response) {
    response.writeHead(200, { 'Content-Type': 'text/plain' , 'Access-Control-Allow-Origin' : 'http://localhost'});
    var url_parts = url.parse(request.url,true);
    var querystring = url_parts.query;

    if(!libAS.exists(querystring.channel_id) || !libAS.exists(querystring.workstamp) || !libAS.exists(querystring.subscriber))
    {
        response.end("Invalid Request");
    }

    var channel = new Channel(querystring.channel_id,cache);
        //get workstamp
        channel.getWorkstamp(function(workstamp) {
        if(!workstamp)
        {
            //If workstamp not found
            response.end("Channel invalid");
        }
        else
        {
            channel.checkSubscriber(querystring.subscriber,function(valid) {
                if(!valid)
                {
                    response.end("Channel invalid");
                }
                else
                {
                    channel.startLoop(querystring.workstamp,response);
                }
            });
        }
                });
}).listen(1111,'localhost');

//----------------------------------CHANNEL HANDLING----------------------------------------//

var Channel = function(id,cache) {
    this.cache = cache;
    this.id = id;
    this.loopLimit = 10; // Almost equal to seconds.
    this.loopCount = 0;
    this.WSDump = null;

    this.getWorkstamp(function(workstamp){
        this.WSDump = workstamp;
    });

};

Channel.prototype.startLoop = function(workstamp,response) {
    _self = this;
    _self.WSDump = workstamp;
        _self.checkUpdates(workstamp,function(updated,current_workstamp){
            if(updated)
            {
                console.log("Updated. Ending");
            }
            else
            {
                if(_self.loopCount<_self.loopLimit)
                {
                    console.log("Not Updated. Continuing with workstamp "+current_workstamp);
                    _self.loopCount++;
                    _self.loop(current_workstamp,response);
                }
                else
                {
                    console.log("Limit reached. Updating current workstamp "+current_workstamp);
                    _self.endResponse(200,response);
                }
            }
        });
};

Channel.prototype.loop = function(workstamp,response) {
    _self = this;
    _self.WSDump = workstamp;
    setTimeout(function() {
        _self.checkUpdates(workstamp,function(updated,current_workstamp){
            if(updated)
            {
                console.log("Updated. Ending");
            }
            else
            {
                if(_self.loopCount<_self.loopLimit)
                {
                    console.log("Not Updated. Continuing with workstamp "+current_workstamp);
                    _self.loopCount++;
                    _self.loop(current_workstamp,response);
                }
                else
                {
                    console.log("Limit reached. Updating current workstamp "+current_workstamp);
                    _self.endResponse(200,response);
                }
            }
        });
    },1000);
};

Channel.prototype.endResponse = function(code,response) {
    if(code === 200)
    {
        json = {"status":200};
    }
    response.end(JSON.stringify(json));
};

Channel.prototype.checkUpdates = function(workstamp,callback) {
    this.getWorkstamp(function(current_workstamp) {
        if(!current_workstamp) callback(false);
        else
        {
            if(workstamp == current_workstamp)
            {
                callback(false,current_workstamp);
            }
            else
            {
                callback(true,current_workstamp);
            }
        }
    });
};

Channel.prototype.getWorkstamp = function(callback) {
    this.cache.get(this.id+':channel'+':workstamp',function(err,data){
        if(err)
        {
            console.log(err);
            callback(false);
        }
        else
        {
            callback(data);
        }
    });
};

Channel.prototype.checkSubscriber = function(id,callback) {
    this.cache.get(this.id+':channel:subscriptions',function(err,data) {
        if(err)
        {
            console.log(err);
            callback(false);
        }
        else
        {
            data = getArray(data);
            for(i=0;i<data.length;i++)
            {
                if(data[i]['id']==id)
                {
                    callback(true);
                    break;
                }
                else
                {
                    if(i == (data.length-1))
                    {
                        callback(false);
                        break;
                    }
                }
            }
        }
    });
};

Channel.prototype.fetch = function(callback) {
    this.cache.get(this.id+':channel',function(err,data){
        if(err)
        {
            console.log(err);
            callback(false);
        }
        else
        {
            callback(getArray(data));
        }
    });
};

var getArray = function(obj) {
    return JSON.parse(obj.toString());
};

当只连接一个客户端时,它就像我想要的那样运行,也就是说,进程在10秒内结束。但是当我同时通过2个客户发送请求时,流程在20s结束。如果是3,那么30s。谁能告诉我这里的问题?我以为每个请求会分别执行相同的代码吗? (PS,我不是很擅长javascript,我为没有文档的代码道歉,我有点匆忙)。

1 个答案:

答案 0 :(得分:0)

解决了它。循环计算在某处混淆的地方。我更改了它以删除原型函数,并使用这样的简单函数:

var http = require('http');
var url = require('url');
var Memcached = require('memcached');
var libAS = require('./libAS');
var cache = new Memcached('localhost:11211');

http.createServer(function(request,response) {
    response.writeHead(200, { 'Content-Type': 'text/plain' , 'Access-Control-Allow-Origin' : 'http://localhost'});
    var url_parts = url.parse(request.url,true);
    var querystring = url_parts.query;
    var channel_id = querystring.channel_id;
    var subscriber = querystring.subscriber;
    var workstamp = querystring.workstamp;

    if(!libAS.exists(querystring.channel_id) || !libAS.exists(querystring.workstamp) || !libAS.exists(querystring.subscriber))
    {
        response.end("Invalid Request");
    }

    fetch(channel_id,cache,function(data){
        if(checkEmpty(data)) endResponse(0,workstamp,response);
        else
        {
            checkSubscriber(channel_id,subscriber,cache,function(valid){
                if(!valid) endResponse(-1,workstamp,response);
                else
                {
                    startLoop(channel_id,workstamp,response,cache);
                }
            });
        }
    });
}).listen(1111,'localhost');

//----------------------------------CHANNEL HANDLING----------------------------------------//

var LoopProp = function(){
    this.count = 0;
    this.limit = 10;
};

var startLoop = function(channel_id,workstamp,response,cache) {
    var current_workstamp = workstamp;
    var prop = new LoopProp();
    checkUpdates(channel_id,current_workstamp,cache,function(updated,new_workstamp){
                if(updated)
                {
                    console.log("Updated. Ending - Old workstamp:"+current_workstamp+" - New workstamp:"+new_workstamp);
                    endResponse(1,new_workstamp,response);
                }
                else
                {
                    current_workstamp = new_workstamp;
                    console.log("Not updated. Workstamp : "+current_workstamp);
                    loop(channel_id,current_workstamp,prop,response,cache);
                }
            });
};

var loop = function(channel_id,workstamp,prop,response,cache) {
    var current_workstamp = workstamp;
    setTimeout(function(){
            checkUpdates(channel_id,current_workstamp,cache,function(updated,new_workstamp){
                if(updated)
                {
                    console.log("Updated. Ending - Old workstamp:"+current_workstamp+" - New workstamp:"+new_workstamp);
                    endResponse(1,new_workstamp,response);
                }
                else
                {
                    current_workstamp = new_workstamp;
                    console.log("Not updated. Workstamp : "+current_workstamp+" - Loop count : "+prop.count);
                    if(prop.count==(prop.limit-1))
                    {
                        endResponse(0,current_workstamp,response);
                    }
                    else
                    {
                        prop.count++;
                        loop(channel_id,current_workstamp,prop,response,cache);
                    }
                }
            });
        },1000);
};

var endResponse = function(code,workstamp,response) {
    response.end(JSON.stringify({'status':code,'workstamp':workstamp}));
};

var checkUpdates = function(channel_id,workstamp,cache,callback) {
    getWorkstamp(channel_id,cache,function(current_workstamp) {
        if(!current_workstamp) callback(false);
        else
        {
            if(workstamp == current_workstamp)
            {
                callback(false,current_workstamp);
            }
            else
            {
                callback(true,current_workstamp);
            }
        }
    });
};

var getWorkstamp = function(channel_id,cache,callback) {
    cache.get(channel_id+':channel'+':workstamp',function(err,data){
        if(err)
        {
            console.log(err);
            callback(false);
        }
        else
        {
            callback(data);
        }
    });
};

var checkSubscriber = function(channel_id,subscriber,cache,callback) {
    cache.get(channel_id+':channel:subscriptions',function(err,data) {
        if(err)
        {
            console.log(err);
            callback(false);
        }
        else
        {
            data = getArray(data);
            for(i=0;i<data.length;i++)
            {
                if(data[i]['id']==subscriber)
                {
                    callback(true);
                    break;
                }
                else
                {
                    if(i == (data.length-1))
                    {
                        callback(false);
                        break;
                    }
                }
            }
        }
    });
};

var fetch = function(channel_id,cache,callback) {
    cache.get(channel_id+':channel',function(err,data){
        if(err)
        {
            console.log(err);
            callback(false);
        }
        else
        {
            callback(data);
        }
    });
};

var checkEmpty = function(obj) {
    if(obj == ':') return true; else return false;
};

var getArray = function(obj) {
    return JSON.parse(obj.toString());
};