阅读体验优化之起点阅读页

原创声明

本文为阅文体验设计 YUX 成员出品,请尊重原创,转载请联系阅文体验设计微信公众号 ( id: YUX_design ) 获取授权,并注明作者、出处和链接。

阅读体验优化之起点阅读页

阅读页作为小说阅读类网站访问量很高的页面,阅读体验上的优化是至关重要的。我有幸在起点项目中负责阅读页的前端开发,成就感满满。

起点中文网访问地址:http://www.qidian.com ,欢迎体验!

在整个起点项目已经有很完善的性能优化体系的情况下,阅读页在改版之后,页面性能统计数据如下:

阅读体验优化之起点阅读页

▲ 上报系统统计数据


阅读体验优化之起点阅读页

▲ 全国访问速度均值 10% 采样结果

由上组统计数据我们可以看到,起点中文网阅读页平均 DOM Ready 的时间为 0.2s ,Onload 的时间为 0.9s ,加载最慢地区页面 Onload 时间也仅为 1.44s 。

这已经充分体现了起点中文网阅读页的优异性能,本篇着重探讨在页面性能已经如此良好的情况下,如何进一步的优化起点中文的阅读体验。本次优化侧重在以下两点:

    一、章节加载逻辑优化;

    二、滚动加载优化-函数节流;

一、章节加载逻辑优化


通常用户在阅读完上一章之后,会明显的看到我们加载下一章的 Loading 状态。这对于用户体验来说影响是比较大的。如果能在用户触发到某一特定时间点的时候,就提前加载好下一章节内容,用户停留在 Loading 的时间就能明显减少甚至感知不到。这种体验上的优化我们称之为无缝阅读。基于这个点我们采取了如下的两种方式:


1. 适当提前 Scroll 触发加载时机;

2. 持续预加载后面章节数据;

1. 适当提前 Scroll 触发加载时机


什么是触发加载时机提前?即当你预知到加载即将被触发,就提前触发当前事件,这可以大大减少用户等待的时间。

起点中文阅读页提前触发事件的机制是,当页面剩余高度小于等于页面视窗的 1.5 倍时,就立即加载下一章节。

阅读体验优化之起点阅读页

可以看到实现原理其实很简单,就是达到触发点去拉取下一章节,实现代码如下:

  1. // 使用函数节流的形式监听scroll事件

  2. $(window).on('scroll', function(){  

  3.  // 获取当前页面高度

  4.  var pageHeight = $(document).height();  

  5.  // 获取滚动条距离页面顶部的距离

  6.  var winSTop = $(window).scrollTop();  

  7.  // 获取浏览器高度

  8.  var winHeight = $(window).height();  

  9.  // 当页面未显示高度页还剩1.5倍视窗高度时,加载

  10.  var cHeight =  2.5 * winHeight;  

  11.  //当剩下小于1。5屏未显示的时候,加载新的章节

  12.  if( pageHeight <= ( winSTop + cHeight ) ){    

  13.    // ... do somethings

  14.  }

  15. });

  16. // 页面初始化的时候主动去触发一次scroll事件

  17. $(window).trigger('scroll');

当写完上述代码后,会发现页面加载下一章节变的快多了,但是在滚动很快的情况下或者数据接口返回较慢的时候,页面还是会显示 Loading 态,如下图所示:


阅读体验优化之起点阅读页

Loading 会 Block 阅读进度,影响用户阅读心情。所以在这种情况下,我们引入第二个体验上的优化点。


2. 持续预加载后面章节数据


什么是预加载?提前加载数据,当用户需要查看时可直接从本地缓存或者内存中读取。


为什么需要预加载?可以从缓存中读取数据,不通过网络传输,速度更加快,无延迟。


利用用户阅读的空余时间,提前加载下面一章节的信息存入内存中,减少用户等待 Loading 的时间,从而达到进一步提升用户体验的目的。

阅读体验优化之起点阅读页

▲ 预加载逻辑流程

上图描述了我们利用内存存储下一章数据的流程。下面具体来看一下代码的逻辑:


1) 首先页面 Load 完之后立马加载一章节内容存储在内存中;

  1. var chapterInfo = {        

  2.    // 标示字段中是否有 章节存储

       isHas: boolean,

  3.    chapterId: 21463,

  4.    content: ''

  5. };

  6. // 是否正在预加载标识

  7. var chapterLoad = false;

2) Scroll 滚动触发逻辑 ,添加预加载章节逻辑,保证页面加载无断续状态。代码如下:

  1. // 使用函数节流的形式监听scroll事件

  2. $(window).on('scroll', function() {

  3. //当正在加载章节时,不再加载下面章节    

  4. if (that.chapterLoad) return false;

  5. // do something ...

  6. // 当剩下小于1.5屏未显示的时候,加载新的章节

  7. if (pageHeight <= (winSTop + cHeight)) {      

  8. // 当内存中有章节存储 && 储存的章节id === 下一张展现至页面上的章节id

  9.    if (chapterInfo.isHas && chapterInfo.id == nextChapterId) {

  10.      // 把内存中的章节append 至页面中,并清除chapterInfo参数中的数据

  11.    } else {      

  12.      // capterLoad 置为true,禁止发送请求

  13.      that.chapterLoad = true;      

  14.      // 发送ajax请求 加载数据 append 至页面

  15.    }

  16.  } else if (!chapterInfo.isHas && !that.chapterLoad) {  

  17.   // 当内存中没有章节信息 && 没有章节正在加载时 进行预先加载

  18.   //重置为true,禁止发送请求

  19.   that.chapterLoad = true;

  20.   chapterInfo.isHas = true;  

  21.   // ajax拉取章节信息至内存 ,并设置 that.chapterLoad = false    

  22.   // 在数据返回存入内存后,回调中主动触发一次 window.scroll 事件,防止在ajax请求时还未返回数据时, 页面已经滚动至底部不再触发scroll 事件,页面出现加载停滞情况

  23.  }

  24. });

从上述代码可以看到预加载和直接 Append 数据至页面中的逻辑是互斥的,既保证页面逻辑清晰,也优化了页面阅读体验,达到我们预期的效果。现在我们来看下页面滚动的效果:

阅读体验优化之起点阅读页

页面加载下一章节的时候几乎没有 Loading 态显示,赞!

二、滚动加载优化-函数节流


做了上述优化之后,页面滚动加载已经很完美了,这个时候我们可以去思考一下代码层面上的优化。在前端领域中滚动加载是一个十分常见的加载机制。监听 window.scroll 事件,判断当前是否到达触发加载的时机,加载后面一段内容。常见的监听事件代码为:

  1. $(window).on('scroll',function(){    

  2.  // ... do somethings  

  3. });

上诉章节预加载就是使用这种 Scroll 监听方式。

但是 window.scroll 事件监听是实时触发的,也就说每隔 16.7ms 就触发一次,单位时间内事件触发的次数过多,会影响系统性能。此时函数节流是一个不错的解决方案。

函数节流是什么意思呢?好比生活中拧紧水龙头的过程,在拧紧这个动作中,我们单位时间内流出的水就会减少,从而达到我们节流的目的。

在代码逻辑中我们通常预先设定一个执行周期,当调用动作的时刻大于或等于执行周期时则执行该动作,然后进入下一个新周期。

我们通过设置一个合适时间间隔来执行 Scroll 事件,以减少请求增加性能。在停止 Scroll 滚动之后,再触发一次滚动事件,处理滚动时机不对,触发不及时的问题。定义一个节流函数,如下:

  1. function throttle(func, wait, mustRun) {    

  2.  var timeout,

  3.  startTime = new Date();  

  4.  return function() {    

  5.    var context = this,

  6.    args = arguments,

  7.    curTime = new Date();    

  8.    // 清除定时器

  9.    clearTimeout(timeout);    

  10.    // 如果达到了规定的触发时间间隔,触发 handler

  11.    if(curTime - startTime >= mustRun) {

  12.      func.apply(context,args);

  13.      startTime = curTime;

  14.    } else {

  15.      // 没达到触发间隔,重新设定定时器

  16.      timeout = setTimeout(func, wait);

  17.    }

  18.  };

  19. };

监听滚动的方式就可以优化成:

  1. // 使用函数节流的形式监听scroll事件

  2. $(window).on('scroll', throttle(function () {        

  3.  // do something

  4. }, 200 ,300));

如下所示,左边是普通 Scroll 事件触发的方式,右边是使用了节流函数触发的方式。使用节流函数的方式明显减少了事件触发的频率,并且在停止滚动的时候也会触发一次 Scroll 事件,防止错过一些特殊的情况,未能执行页面下拉加载事件。

阅读体验优化之起点阅读页

最终我们在没有影响页面滚动加载体验的情况下,节省了浏览器的性能开销,完美。

结尾


第一次做阅读相关的项目,并负责如此重要的一个页面,我融入了自己的想法,优化阅读体验,最终达到了我要的效果,我很满意。

一个细节的优化是可以决定产品的好坏的,良好的用户体验,会吸引跟多的用户,获得更多的称赞。针对阅读体验上的优化,我们其实能做的还有很多,希望之后可以再进一步的优化。


阅读体验优化之起点阅读页

本文作者:刘文涛

转载请向阅文体验设计微信公众号 ( id: YUX_design ) 获取授权,并注明作者、出处和链接。

本篇文章来源于微信公众号: 阅文体验设计YUX

UI/UX

优化设计文化—Google设计主管访谈 | 翻译02

2017-7-18 8:35:00

UI/UX

『淘宝造物节』开放品牌设计(上集)

2017-7-19 18:45:29

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索