前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如果被耗时任务拖累,可能是姿势不对

如果被耗时任务拖累,可能是姿势不对

作者头像
IMWeb前端团队
发布2017-12-29 16:06:18
8010
发布2017-12-29 16:06:18
举报
文章被收录于专栏:IMWeb前端团队IMWeb前端团队

如果被耗时任务拖累,可能是姿势不对

在业务中,有时候需要处理一些相对耗时的事情,而且还有一些其他的逻辑还可能会依赖这个耗时任务。诚然,太久的耗时会对用户体验不好。

本文就自己在业务中的一次实践,从其中一个小角度来分享看法,纯属个人观点,如有纰漏之处,还望指教。

背景

我们的项目是Hybrid混合应用,页面运行在手机QQ(后续简称手Q)中。在我们的业务中,我们有个新上线的业务,进入页面A之后,需要根据用户的地理位置(可以用缓存)去跳转到新业务页面B(灰度)或者继续渲染页面A。

业务流程图
业务流程图

最正经的实现方案

很容易想到的最正(diao)经(si)的一种实现方案,就是先获得当前用户的地理位置,拿到地理位置之后,还要去调用后台CGI接口,获得当前用户处于的城市,然后再根据这个城市,判断是否应该跳转到特定的页面。

伪代码实现

使用伪代码表示如下:

代码语言:javascript
复制
// 调用手Q接口获取当前用户的地理位置,data中包含了经度和纬度
getLocation(function(data){
    // 调用CGI接口,获得当前的城市信息
    getCity(data, function(res){
        if(res.city=='深圳') {
            // 跳转到页面B
            jumpTo('pageB');
        } else {
            // 继续渲染页面A
            init();
        }
    });
});

你真不是来捣乱的吧

理论是美好的,但是...

  1. 客户端的 getLocation 接口去获取用户当前地理位置,其实是非常耗时的操作。经过多次测试,获取一次的耗时在 2s ~ 5s 左右,即便可以使用其缓存,也需要花费 200ms 以上,而且还很不稳定。要知道当时测试的环境是 wifi 下,而且测试机是比较新的配置中等的小米4。如果真实用户拿着一个配置不高的手机,然后在网络状况不好的场景下,我猜测耗时会更高。
  2. 除了客户端的接口会耗时之外,还需要调用一次后台CGI,由于这个CGI接口已经在现网运行过一段时间,从检测的数据来说,wifi下请求一次耗时大概在 50ms ~ 150ms 左右,如果在非wifi场景下,这个时间肯定会更耗时。
  3. webview本身初始化时间、js/css/img文件、其他CGI请求等的耗时等累积也在几百毫秒以上。

综上,如果用户第一次没有缓存的情况下,或者网络状况不好,或者他用的手机属于比较亲(di)民(duan)的那种,那么,当用户看着加载的菊花图一直转啊转,耳边不禁想起“跟着我左手右手一个慢动作,右手左手慢动作重播”时,我想应该没有多少人是会有耐心等待的。

进一步分析

上文讨论的最常规的方案显然会有体验的问题,怎么办?

需要时效性吗

对我们造成困扰的缘故,在于我们常会有一种程序员的思维(情怀),认为流程就是这样啊,这样才能够实现功能,而且是最精确最实时的。你看每次你进来我们的页面我们就对你进行一次判断,避免上一分钟你在城市A,下一分钟到了城市B会出问题。

没错,追求精确和完美并不是坏事,但这会付出时间成本,在这里而言,我们真的那么需要时效性吗?80% 以上的用户很少会在几小时或一天内会离开一座城市;即便离开了,看得到我们的新页面了,也没任何关系,更何况我们是在灰度,多几个人看到关系不大,以后迟早大家都看得到。

缓存地理位置

既然没有时效性的要求,要处理的业务也不是敏感,那么就缓存呗。且不是说缓存客户端的 getLocation 结果,而是直接缓存最后计算得到的城市名。

代码语言:javascript
复制
if (!existCity) {
    // 调用手Q接口获取当前用户的地理位置,data中包含了经度和纬度
    getLocation(function(data) {
        // 调用CGI接口,获得当前的城市信息
        getCity(data, function(res) {
            if (res.city == '深圳') {
                // 跳转到页面B
                jumpTo('pageB');
            } else {
                // 继续渲染页面A
                init();
            }
        });
    });
} else {
    // 继续渲染页面A
    init();
}

用户的第一次

即便我们可以缓存地理位置,那用户第一次进来没有缓存时,依然逃脱不了加载缓慢的命运。难道要告诉用户说“忍一忍,第一次都会痛苦的,下一次再来时你就会感到畅快了”?对用户的第一次不负责,用户可能就不会给你第二次了。

提前准备缓存

既然在用户要的时候无法满足他们的需求,那么,何不提前准备呢?比如在一个浪漫温馨你侬我侬的夜晚,气氛恰到好处,却发现缺少了“必要的东西”,这时候需要你大晚上下楼跑几条街的店里去贡献一点GDP,你会崩溃的。

回到我们说的场景,似乎也可以提前发一个版本,在这个版本中,增加一个小功能,就是在用户正常打开页面之后,再私下去获取到用户的位置,并放入到本地 localStorage 中缓存结果。等到真实版本发出之后,由于之前已经有缓存结果了,那么就省略了调用接口的过程,而换成了判断 localStorage 缓存了,这个性能立即就上来了。

先领劵,再享受优惠

提前准备缓存的办法理论上是行得通的,但麻烦啊,要新发版本,而且为了一小部分灰度的人,影响了大部分人的体验(新版本发了之后之前的离线包或js文件缓存就失效了,何况他们又享受不到新的业务,浪费),有点不值得。就比如“必要的东西”是准备了,但没机会使用,也就浪费了。

进一步分析,还可以有进一步的优化。简单而言,就是用户第一次进来时,全都展示原始的页面A后,后台开始获取城市信息,并打上缓存(发放优惠劵,但也不是所有人都发,比如乞丐之类的就忽略了);第二次之后再来时,有指定的缓存了就直接跳转到页面B了(凭借优惠券享受优惠)。实际上我们最终的方案就是这种。

最后的方案和总结

上面说到了我们最终的方案是“先领劵再享受优惠”的思路。其实这和离线包的机制是类似的,如果本地没有离线包,则返回线上的,同时手Q后台线程会去拉取离线包到本地;等第二次再来时,由于有了离线包,这时候就直接使用离线包的内容,提升了用户体验。

很罗嗦的记录了最近在某个业务中遇到的情况,我想表达的内容也比较简单,就是如果我们依赖了很耗时的业务时,可以换种思维,换种姿势,例如将同步处理修改为异步处理,或者思考其他的方式,来解决技术无法解决问题。很典型的还有我们常见的进度条或者菊花loading图,也是从另外的方面的努力,来“掩盖”耗时的问题,而耗时问题有时候是无法避免的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如果被耗时任务拖累,可能是姿势不对
    • 背景
      • 最正经的实现方案
        • 伪代码实现
        • 你真不是来捣乱的吧
      • 进一步分析
        • 需要时效性吗
        • 缓存地理位置
        • 用户的第一次
        • 提前准备缓存
        • 先领劵,再享受优惠
      • 最后的方案和总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档