网页聊天室之修改经验总结

1.一个浏览器同时登录多个用户session互相冲突如何解决?

由于同一个浏览器默认会共享session,所以无法在同一浏览器下登录多个用户,解决方法如下:

  • Firefox:编辑快捷方式的目标,后面加上 -p -no-remote
  • Chrome:打开新的隐身窗口 或者 添加新用户
  • IE:文件 --> 新的会话

2.Socket 服务端如何判断消息该发送给谁?

解决办法:
1.首先在服务端创建数组userId用来保存每个登录用户的sockettoChat数组保存用户的聊天对象_id
2.每次用户登录会emit一个add user,服务器接收到这个请求,保存接受的用户socket和聊天对象id
3.有3种情况要处理

  • a. 对方不在线,即userList [ 对方ID ]NULL,则emit给用户对方不在线,并且用户本地保存消息,标记消息为未读,status为 0
  • b. 对方B在线,但正在与其他用户C聊天,chatTo数组保存聊天对象的Id,判断对方的聊天对象是否是自己,写成代码即为 chatTo[chatTo[A]] == A,其中chatTo [ A ]就是B,如果false则emit给对方客户端增加未读消息数量并显示,status为0,保存消息进数据库
  • c. 对方在线且聊天对象正是自己,则emit消息给对方,status为 1,保存消息进数据库
var io = require('socket.io').listen(server);
var userId = {};
var toChat = {};

io.on('connection', function(socket){
  socket.on('add user', function (data) {
    console.log(socket.id);
    socket.name = data.from;
    toChat[data.from] = data.to;//保存用户聊天对象
    userId[data.from] = socket;//每次进入都要socket.id都要变一次
  });
  socket.on('chat message', function(msg){
    // console.log(msg);
      var data = {
        msg: msg.content,
        ctn: msg.content,
        from: msg.from,
        to: msg.to,
        status: 1
      };
    if(toChat[toChat[socket.name]] == socket.name && userId[msg.to]) {
      //直接发送
      userId[msg.to].emit('chat message', data);
    } else if(userId[msg.to] && toChat[toChat[socket.name]] != socket.name) {
        data.status = 2;
      userId[msg.to].emit('chat message', data);
    } else {
        data.status = 0;
      userId[msg.from].emit('chat message', data);
    }
  });
  socket.on('disconnect', function () {
    //用户退出提醒对方
    if(userId[toChat[socket.name]] && toChat[toChat[socket.name]] == socket.name) {//判断对方聊天的对象是否是自己
      userId[toChat[socket.name]].emit('user left', "对方退出!");
    }
    delete userId[socket.name];
    delete toChat[socket.name];
  });
});

3. 页面修改,将原本需要跳转新页面改成点击增加div

通过点击后创建制定的html,隐藏全部class的div,在显示指定id的div即可实现

$('[data-toggle="chat"]').on('click', function (e) {
        e.preventDefault();
        var $this = $(this);
        fid = $this.data('id');
        name = $this.children('.username').html();
        createChat();
        $(".chat-default").hide();
        $(".box-send").show();
    });

function createChat() {
    if (chatSession.indexOf(fid) === -1) {
        chatSession.push(fid);
    }
    var data = {
        from: uid,
        to: fid
    };
    socket.emit('add user', data);
    toggleChatView();
}

//切换聊天窗口
function toggleChatView() {
    if ($("#t"+fid).length == 0 && $("#c"+fid).length == 0) {
        $(".chat-area").prepend('<div class="box-hd" id="t'+fid+'"> <div class="info-friend">'+name+'</div><div class="history-msg">聊天记录</div></div><div class="box-bd" id="c'+fid+'"><ul class="messages" id="m'+fid+'"></ul></div>');
    }
    $(".box-bd").css("height", "528px");
    getUnreadMsg(fid);
    updateMsgStatus(fid);
    $(".box-hd").hide();
    $(".box-bd").hide();
    $(".box-send").show();
    $("#t"+fid).show();
    $("#c"+fid).show();
}

//切换聊天记录窗口
function toggleHistoryView() {
    $("#mh"+fid).html('');
    if ($("#th"+fid).length == 0 && $("#ch"+fid).length == 0) {
        $(".chat-area").prepend('<div class="box-hd" id="th'+fid+'"> <div class="info-friend">与'+name+'的聊天记录</div><div class="history-back">返回</div> </div><div class="box-bd" id="ch'+fid+'"><ul class="messages" id="mh'+fid+'"></ul></div>');
    }
    getHistoryMsg();
    $(".box-hd").hide();
    $(".box-bd").hide();
    $(".box-send").hide();
    $(".box-bd").css("height", "709px");
    $("#th"+fid).show();
    $("#ch"+fid).show();
}

4. 对聊天记录的获取

前一版本只能显示对方发送的消息,改版后的聊天记录获取了两者之间的全部消息并按照发送时间排序显示

Async waterfall的使用

waterfall(tasks, [callback]) (多个函数依次执行,且前一个的输出为后一个的输入)

按顺序依次执行多个函数。每一个函数产生的值,都将传给下一个函数。如果中途出错,后面的函数将不会被执行。错误信息以及之前产生的结果,将传给waterfall最终的callback。

var async = require('async');
var a = 10;
async.waterfall([
    function(cb) {
        console.log("getb")
        setTimeout(function() {
            if (a == 0) {
                cb(new Error("a不能为0"));
            } else {
                var b = 1 / a;
                cb(null, b); //在这里通过回调函数把b传给下一个函数,记得一定要加上null,才能调用数组中得下一个函数,否则,会直接调用最终的回调函数,然后结束函数,则后面的函数将不再执行
                //如果这里写成cb(b);
                //结果会变成:
                /**
                 *getb
                 *0.1
                 **/
            }
        }, 1000);
    },
    function(b, cb) {
        setTimeout(function() {
            console.log("getc")
            var c = b + 1;
            cb(null,c);
        }, 1000);
    }
], function(err, result) {
    if (err) {
        console.log(err);
    } else {
        console.log('c:' + result)
    }
});

当a = 0时,会直接抛出错误,输出如下:getbError: a不能为0先执行了第一个函数,在第一个函数中抛出异常之后,直接执行最终的回调函数,并没有接着执行第二个函数。a = 10 时,输出如下:getbgetc1.1先执行了第一个函数,然后把第一个函数算出的b传给了第二个函数,再次算出第二个函数中得C,传给最终的结果result。

underscore 对象数组排序 sortBy
_.sortBy([1, 2, 3], function(n) {
 return Math.sin(n);
});

上面是官方示例默认排序方式是正序排列
如果你的数组是一个对象组合

var arr=
[
{"key":"key1","value":"value1","createTime":"124573216"},
{"key":"key2","value":"value2","createTime":"124593216"},
{"key":"key3","value":"value3","createTime":"124596216"},
{"key":"key4","value":"value4","createTime":"124596286"},
{"key":"key5","value":"value5","createTime":"124596289"},
]

当你要对上面的数组中的 createTime 进行排序时

//正序排列
_.sortBy(arr, function(item) {
  return item.createTime;
});

//如何倒序排列
_.sortBy(arr, function(item) {
  return -item.createTime;
});
项目中的使用
//查看历史消息记录
exports.findHistoryMsg = function (data, cb) {
    var conditions1 = {"from": data.from, "to": data.to};
    var conditions2 = {"from": data.to, "to": data.from};
    
    async.waterfall([
        function (cb) {
            Message.find(conditions1, function (err, data) {
                var messageList = new Array();
                for(var i =0; i < data.length; i++) {
                    messageList.push(data[i].toObject());
                }
                cb(err, messageList);
            });
        },
        function (doc, cb) {
            Message.find(conditions2, function (err, data) {
                // var messageList = new Array();
                for(var i = 0; i < data.length; i++) {
                    doc.push(data[i].toObject());
                }
                var result = _.sortBy(doc, function (item) {
                    return item.meta.createAt;
                });
                cb(err, result);
            });
        }
    ], function (err, result) {
        cb(true, result);
        console.log(result);
    });

};
Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容

  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,590评论 0 15
  • 从10月1号到13号,用了大概80%的时间基本实现了一个聊天室应该具备的基本功能: 用户登录注册 添加好友 (点击...
    淡就加点盐阅读 2,523评论 0 12
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,196评论 0 4
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,139评论 11 349
  • 2016的最后一天,在朋友圈里摇到一个新年签-新生:只要你想,未来的每一天都是一次新生。 回顾我的整个...
    怿悅阅读 179评论 0 0