goChat项目总结

来源:互联网 发布:检测 android ios js 编辑:程序博客网 时间:2024/06/04 00:25

1.背景概述

项目概述:能够实现在线聊天功能的SPA应用。
技术栈:jquery+WebSocket+nodejs+mongoose。
源代码:https://github.com/zjjxj/goChat

2.项目详情

很久以前就想来写个项目过程记录文档,因为整个项目过程中实在时学到了太多东西想让我有记录下来的冲动。

没做这个项目之前,很多次都有听说SPA应用,但是一直都是一知半解,之后看了一本SPA实践教程的书,说实话,看的很吃力。很多设计理念和代码组织方式没办法理解。之后就打算自己动手先做起来。整个项目做下来,到现在也只敢说完成了大概70%,很多细节还没有实现。但对很多概念也有了自己的理解。

SPA应用通俗点来说就是整个应用的功能都在一个页面上完成,也就是后端不再进行页面渲染和一些业务逻辑的工作,把这些任务都交给前端来处理。所以前端的代码量就会番倍的增长,那前端的架构设计代码组织就显的格外的重要。下面具体来看这个项目。

业务流程:

首先用户要通过填入用户名,密码,手机号进行账号的注册。注册成功后即可通过登录进入聊天室。关于注册,我就是用一个表单将信息提交到后台进行处理保存的,没有什么特殊的设计,所以接下来主要讲一下用户登录开始的一些业务流程。

  1. 用户填写账户名密码,点击登录按钮
  2. 将信息发往后台进行验证。若信息正确,则的登录成功,进入用户个人界面,此时后台也会保存用户的登录状态,并向所有在线人员广播,该用户已上线,并对所有在线人员的好友列表进行更新。若不正确,则返回登录失败的提示信息。
  3. 用户进入聊天室以后,默认是处于群聊状态,用户可双击聊天室左侧的在线人员列表进入私聊状态。
  4. 用户点击登出按钮,即表示退出聊天室。断开与后台的连接,后台就会进行相应的信息更新,并向所有其他在线用户广播该用户已下线,并进行所有在线用户好友列表的更新。

具体实现:

1.前端采用MVP的架构模模式:

这里写图片描述

view层:就是页面的呈现

presenter层:就是控制层,主要负责功能模块的管理,前端路由的管理。起一个桥梁作用。他要响应用户事件,将信息传递给model层进行处理,要订阅model层发布的消息,通知view层进行视图更新。

model层:是唯一和后台进行交互的模块。主要负责逻辑和数据管理。为控制层提供数据和业务逻辑。向前只与控制层交互,不依赖用户界面。

2.状态管理:
采用哈希进行应用状态的管理,保证浏览器的前进后退按钮可用。

当用户状态个改变时,比如用户点击登出按钮,就会进行哈希值的变更,通过监听浏览器的onhashchange事件响应这个变更,调用view层进行视图上的更新。

3.代码组织
前端采用requirejs进行代码的模块化组织,主要是为了进行依赖管理性能优化(异步加载模块的特性)。

4.与服务器通信
主要采用socketio与服务器进行通信,便利的全双工双向通信跨浏览器的优势

5.样式管理
页面基准样式文件+功能模块样式分开管理
响应式布局

5.性能优化
发布前进行代码的压缩合并,减少HTTP请求数
采用appcache进行本地存储,首次请求后就将静态文件缓存到本地。
通过修改className一次性修改样式代替一步步修改。减少页面的重排重绘。
使用CDN缓存引入库文件。

3.疑问总结

(主要是面试中被问到的点)

1.详细说明在整个从登录到聊天再到登出的内部实现细节?

—>用户登录
—>presenter层监听用户登录的点击事件,调用model层的login方法,并将用户登录信息传过去
—>model层建立起该用户到服务器的socket连接,并触发login事件(socket.emit(“logIn”, obj))。
—>服务器通过监听connection事件监听客户端的连接,之后通过监听login事件对客户端发来的消息进行处理,验证信息。如果信息正确,则触发loginsuccess事件。否则,则触发其他相应事件。
—>model层通过socket.on监听相应服务器事件,如果登录成功,则发布loginsuccess自定义事件。
—>相应的控制层订阅model层发布的事件,并在当事件发生时调用view层进行视图更新,包括布局更新,好友列表更新。并在状态改变时更改hash。比如登录成功后,将hash改为用户名。
—>进入用户个人界面,用户通过点击聊天滑块展开聊天室。初始默认时在群聊状态。用户可以通过双击好友列表进入与相应好友的私聊模式。
—>当用户点击发送消息按钮,控制层响应相应事件,调用model层的say功能,并将消息内容,发送方,接受方作为参数传给model层。
—>model层通过socket.emit触发say事件与服务器通信,并将相应信息传递给服务器。
—>服务器监听ask事件,并通过发送方,接收方信息判断应该将消息发给谁,应该触发什么事件。
socket.emit() :向建立该连接的客户端广播
socket.broadcast.emit() :向除去建立该连接的客户端的所有客户端广播
io.sockets.emit() :向所有客户端广播,等同于上面两个的和
—>model层监听相应消息,再发布相应的自定义事件。
—>用户点击登出按钮,控制层响应,将消息传至model层,model层触发disconnect事件断开该用户与服务器的socket连接,服务器监听该事件,进行在线人员的更新,并向其他所有在线人员广播该用户下线。
—>model层监听到了服务器的广播事件,并进行响应自定义事件鄂发布。
—>控制层调用视图层进行响应的视图更新。

2.怎样进行模块间的信息传递的?(model层怎样向control层传递信息的?control层又是怎样向model层和view层传递信息的?)

control层通过监听客户端相应的DOM事件响应客户端动作
control层通过调用model层的公开方法将信息传递给model层
model层socket连接,emit和on方法与服务器通信,通过发布自定义事件,为control层提供数据更新。
control层订阅model层的自定义事件,调用view层进行相应的视图更新。

3.具体怎样实现私聊和群聊的功能的?功能间怎样进行切换的?
每次进行消息发送的时候,控制层会将一个包含了发送者,接收者,消息内容的一个对象发向model层,如果是群发,接受者就是“all”,用户双击某好友头像,接受者就是好友ID。model层再将这个对象作为参数传到后台,后台再根据这个参数决定消息 的广播方式。

4.socketio实现全双工双向通信具体时怎样实现的?

首先由客户端向服务器建立一个socket连接
将 socket.io 绑定到服务器上,于是任何连接到该服务器的客户端都具备了实时通信功能。并返回该新连接对象,接下来我们就可以通过该连接对象(socket)与客户端进行通信了。
客户端和服务器都有on和emit这两个函数,就能很方便的进行双向通信。

5.后端路由怎样配合前端路由?

前端路由改变,后端也做相应的response。保持前后端的路由状态的同步即可,也不必返回什么实质性的响应。

6.头像上传功能是怎样实现的?在数据库中怎样存头像?

FormData对象(ajax)向服务器异步发送一个二进制的图片文件,
服务器通过formidable模块来进行二进制图片文件的接收,这个模块可以通过上传路径和和文件后缀名的设置将上传的二进制图片以png jpg的格式保存在文件目录下,mongoDB中保存的用户头像信息就是对应图片的路径。
当我们需要将头像发到客户端时,就把图片文件转换成base64编码的形式发向客户端。

7.前端路由管理还有什么方案吗?为什么要选择hash管理?

history.pushState(replaceState)/window.popState事件
1. 每当激活的历史记录发生变化时,才会触发popstate事件,也就是说当我们在使用history API改变浏览器的url时,仍需要额外的步骤去触发 popstate 事件,比如点击 前进后退按钮或调用 history.back() history.forward() 等方法。
2. 兼容性不如hash,要求IE8+

location.hash/window.hashchange事件
只要hash值发生改变即可触发事件。
对于低版本的浏览器,例如IE6等等,不支持 hashchange 事件。这个时候我们只能通过 setInterval 设置心跳的方式去模拟 hashchange。

0 0
原创粉丝点击