1.一个浏览器同时登录多个用户session互相冲突如何解决?
由于同一个浏览器默认会共享session,所以无法在同一浏览器下登录多个用户,解决方法如下:
- Firefox:编辑快捷方式的目标,后面加上 -p -no-remote
- Chrome:打开新的隐身窗口 或者 添加新用户
- IE:文件 --> 新的会话
2.Socket 服务端如何判断消息该发送给谁?
解决办法:
1.首先在服务端创建数组userId
用来保存每个登录用户的socket
,toChat
数组保存用户的聊天对象_id
2.每次用户登录会emi
t一个add use
r,服务器接收到这个请求,保存接受的用户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);
});
};