【用户体验】加载——Websocket与加载在前端交互上的体验提升(加入用户体验计划会让手机变卡吗)
 南窗  分类:IT技术  人气:296  回帖:0  发布于1年前 收藏

前言

加载,顾名思义,就是将一些信息,从A载到B,这个过程类似运货,而这个过程不是瞬间发生的,就比如把我从深圳运到广州,用复兴号运我需要10分钟,这个就是加载时间。信息从服务器运到本地,从本地运到服务器也需要一定的时间。

无缝加载,是提升加载体验的一种办法,在加载的过程中,用户可无法做其他事情,而过程又很漫长的情况下用户心情就会很烦躁,比如在高铁上我不能玩任何游戏,也没用书给我阅读,只能静坐着等待到达广州。如果我在这期间开ktv,开斗地主,整个过程就不会无聊了,而且我也不只能静坐等待。


例子

清晰明了的过程

一趟列车从广州开往北京,沿途要经过很多站,如果把列车的窗口门口能看到外界的都封堵上,也没有显示屏告诉你现在开到了哪里,心里一定会很着急,甚至不知道列车有没有开动,开的方向对不对。加载也如此,用户操作后没有反馈,或是久久没有结果,会让用户觉得是不是自己的动作没有生效,是不是自己的电脑卡住了

此时有一个指示,告诉乘客“当前在郑州,还有x站到达北京”,体验上提升了几亿个数量级。如果此时再加上列车速度,更能让乘客感觉到“这车真快”,心理上更加舒服

而程序上,用户按下按钮后,反馈上的交流很重要,运行一段复杂程序时,尽可能把关键步骤告诉用户,比如“正在启动”、“正在初始化”、“正在处理”、“正在保存”。

不打断的体验

来源于一次对话

在新游戏《崩坏:星穹铁道》中,每次切后台重进或断网重连时,加载的画面不像崩坏3中叠了一层加载中的layer阻止用户操作,而是塞到了右上角进行加载

崩坏3中的断网加载

而这样的好处就是即使经历了某些不该经历的经历之后,用户依然能够正常操作游戏本身,而不用等待加载完毕。

这就是无缝加载的要点,不影响操作

DEMO

本期以websocket通信为例子,nodejs作为后端。

服务端模拟

这里有一个后端,表示当前端发送websocket消息时,后端回复一个JSON消息:

var express = require('express')
var app = express()
require('express-ws')(app)

app.ws('/load', (ws, req) => {
    ws.on('message', (msg) => {
        ws.send(new Date().getTime())
        setTimeout(() => {
            ws.send(JSON.stringify({
                status: true,
                time: new Date().getTime()
            }))
        }, 2000)
    })
})

app.listen(4003);

setTimeout模拟了加载的动作,表示耗时2s

前端模拟

建立一个websocket连接,并且监听websocket传来的消息

var ws = new WebSocket('ws://localhost:4003/load');
    ws.onmessage = function (data) {
        console.log(data.data)
    }

如果此时我们在控制台操作,得到的结果就是

按下回车后,浏览器并没有任何动作,此时我并不知道是否发送成功,只能静等2s后才能接收到后端发来的信息。

此时加入动画,加载器组件来自Ar-Sr-Na:ai.arsrna.cn 里的所有应用均为此控件

发送事件之前,将该进度条隐藏,发送按钮按下后,显示进度条,成功后再次隐藏

首先,让进度条隐藏

定义发送接收事件,并绑定隐藏事件

var ws = new WebSocket('ws://localhost:4003/load');
    ws.onmessage = function (data) {
        var msg=JSON.parse(data.data)
        console.log(msg)
        if(msg.status) $('#logProgress').hide()
    }

    function fischl() {
        $('#logProgress').show()
        ws.send('')
    }

这样一来,加载过程就清晰了,用户知道自己做的事件有所反馈

“缝”

如上面所说,崩坏3的加载确实有些差劲,我们把它放到三维视图看看这么差劲的加载是怎么回事

甚至

在加载过程中,应用弹了一个非常阴间的加载动画层,阻止了整个应用的操作,只能静待加载完毕后加载层的消失

而在《崩坏:星穹铁道》中,不是大面积的加载,而是仅把加载动画的位置换到了右上角

从而避免挡住用户移动视角,移动人物

这样看似很简单的一个操作,对用户体验的影响极大,改起来也不复杂,就上面例子而言,如果我们把整个加载中覆盖整个body层,就是崩坏3的暴力加载,如果做到小进度条,就是不影响体验的加载。

重连

由于前端websocket断开后并不会自动重连,而后端也不能主动向前端发起连接,所以一旦断开,这个连接如果不再次连上,就永远失去了连接

但是,websocket对象有一个监听断连事件,一旦检测到断连,就重复进行重连

不过要注意的是,如果这个通信不重要,断开一段时间也不会影响用户在本地进行的操作,重连过程不需要搞那么重大

一个稍微小的提示就好,尽量不要打断用户的操作

例如上面的例子

ws.onclose = function (data) {
        $('#lostConn').show();
        //尝试重连的callback
        reConnect()
    }

逻辑

尝试重连操作的方法,就是当发现断连时,再次连接

function reConnect() {
        ws = new WebSocket('ws://localhost:4003/load');
    }

但是这样做会出现一个问题,当第二次尝试失败时,将不会继续进行下一次重连,而且间隔很长,所以此时可以使用间隔尝试的方式,一直重连直到成功

function reconnect() {
        $('#lostConn').show();
        reConnectTimes++
        $('#text2').html(`正在尝试找回小姐 第 ${reConnectTimes} 次`);
         if (lockReconnect) $('#lostConn').hide();return
        $('#lostConn').show();
        lockReconnect = true;
        setTimeout(function () {
            setWebsocket();
            lockReconnect = false;
        }, 1000);//断开后2s自动重连
    }

把连接websocket的事件封装为方法,把上面的代码一同加入

var lockReconnect = false;//websocket连接状态,避免重复连接
    var reConnectTimes = 0;
    setWebsocket()
    function setWebsocket() {
        ws = new WebSocket('ws://localhost:4003/load');

        ws.onmessage = function (data) {
            var msg = JSON.parse(data.data)
            console.log(msg)
            if (msg.status) $('#logProgress').hide()
        }

        ws.onclose = function (event) {
            console.log("断连");
            reconnect();
        }

        ws.onerror = function (event) {
            console.log("错误");
            reconnect();
        }
    }

则总逻辑代码如下:

var lockReconnect = false;//websocket连接状态,避免重复连接
    setWebsocket()
    function setWebsocket() {
        ws = new WebSocket('ws://localhost:4003/load');
        ws.onmessage = function (data) {
           //消息回调 data.data
        }

        ws.onclose = function (event) {
            //console.log("断连");
            reconnect();
        }

        ws.onerror = function (event) {
            //console.log("错误");
            reconnect();
        }
    }

function reconnect() {
        if (lockReconnect) return;
        lockReconnect = true;
        setTimeout(function () {
            setWebsocket();
            lockReconnect = false;
        }, 1000);//断开后1s自动重连
    }

演示效果

正常情况下

服务端主动断开

再次启动效果如正常情况。

总结

对于一些很不重要的消息,在前端展示其重连加载时,应使用后台默默加载或者稍微提示的方式。例如本地计算的项目,不怎么依赖服务器的项目。

对于中等级别的连接,本地可以计算,但是部分来自服务端,可以采用用户提示式的加载。例如原神从后台切回前台时重新从服务器获取信息的场景,此时人物允许移动转视角操作,但是敏感项目例如充值,产生伤害等应先等待服务器做出相应回复。

对于完全依赖服务端的应用,应采取隔断交互的措施,防止用户在客户端进行操作,得不到服务器验证从而造成恶意修改数据的后果。例如充值场景,在服务器那边没收到“钱”之前,一定不能让客户端提前回调。


Powered by Ar-Sr-Na

2023-5-1

 标签:实时通信,

讨论这个帖子(0)垃圾回帖将一律封号处理……