• 我是这样开启列表定时刷新的


    前言

    前段时间写了一个列表框架公共组件,可以快速灵活搭建各种列表页面,且具有高扩展性。

    开发背景:有一个内容管理系统(项目采用vue框架,UI框架使用view-design),内容种类不断的在扩展,最开始的文章,后来的游戏,接下来的教程……
    每一种内容都有:待处理列表,已提交列表,已发布列表,回收站列表,草稿箱。每一种列表的特点都不太相同,却基本是一个模式:
    1、筛选排序条件各不相同,有的列表没有筛选排序条件,改变条件立即同步刷新列表(使用时,可以灵活定制各自的筛选排序)
    2、有些列表需要记住并回显上次的选择的条件,甚至记住并标记出上次查看的列表项
    3、有的列表需要对列表项进行多选,在此基础上进行批量操作(如批量删除,批量上下架),或者批量上传配音等,有的列表什么都不需要(可以扩展其他批量操作)
    4、有的列表需要周期性的更新数据,有的不需要
    由于数据的差异,已有列表不能复用。于是便开发出一个列表框架 ListFrame:
    使用它,只需要提供接口和列表item样式,就可以快速定制各种列表改变搜索及时刷新,分页控制,多选控制,周期更新,条件记忆等逻辑,完全不用关心了,ListFrame 可灵活配置开启。

    这也算是我花了很多心思的得意之作了[憨笑],很多设计思路一直想分享出来(技术上没什么,都是正常的vue技术),但真正写的时候却无从下笔 —— 最不好讲的就是设计了,这是个需要靠领悟的东西,所以我就选一个最好讲的点——定时刷新列表的实现来分享了!

    通常的做法

    定时更新数据,核心是 setInterval 创建一个定时器,通常我们是这么做的:
    1、当组件加载时创建一个定时器,定期调用请求接口;当组件销毁时清理掉这个定时器。这是两个不同的 hook,需要一个状态变量 timmer 记录定时器 id 。
    2、由于用户可能点击搜索等 主动触发页面更新,所以我们需要做一个防抖,需要一个变量 lastReqTime 记录上次的更新时间,然后基于这个时间在定时刷新。
    3、外界需要选择是否开启定期刷新,所以有一个boolean类型的prop 
    核心代码如下:

      props: {
    ... ... // 其他代码省略 autoRefresh: { type: Boolean,
    default: false } }, data() { return {
    ... ... // 其他代码省略 lastReqTime:
    0, timmer: null }; }, methods: {
    ... ... // 其他方法省略
    // 分页请求数据的method: async initPage(pageNo = 1) { this.lastReqTime = Date.now(); ... ... // 其他代码省略 this.lastReqTime = Date.now(); } }, mounted() { if (this.autoRefresh) { this.timmer = setInterval(() => { if (Date.now() >= this.lastReqTime + 30000) { // 每30秒更新一次列表 this.initPage(this.pageNo); } }, 1000); // 每秒中确定一次 }
      ... ... // 其他代码省略 }, beforeDestroy() { clearInterval(
    this.timmer); }

    这段代码的最大问题是逻辑分散,而且为了一个定期更新数据,产生了两个状态,还污染了initPage方法
    别人要想看懂你是怎么实现的,要到处找逻辑,很不容易理解。如果这个组件只有一个功能还好,毕竟就一个功能,问题是还有很多其他功能。

    更好的做法 

    代码是写给人看的(尽管是给机器执行的,但维护的还是人) 把逻辑尽可能放在一起(即所谓的内聚)很重要:(具体看下面代码中加粗的注释)

      props: {
    ... ... // 其他props省略 autoRefresh: { type: Boolean,
    default: false } }, mounted() { if (this.autoRefresh) {
        // 所有逻辑都在一起,其他人阅读时不用到处找代码了(整体抽取 或 移除都很方便)
    // 下面lastReqTime 和 timmer 就是一个普通的局部变量了,不是data中的状态了 let lastReqTime
    = 0; const cycleTime = 30000; const tickTime = 1000;

        // 使用代理模式 来记录lastReqTime 而非污染原来的 initPage : const oldFn
    = this.initPage; this.initPage = function(...params) { lastReqTime = Date.now(); // 必须return,保持一致 return oldFn(...params).then(res => { lastReqTime = Date.now(); return res; }); };
    // 定时器的创建 与销毁 : const timmer
    = setInterval(() => { if (Date.now() >= lastReqTime + cycleTime) { this.initPage(this.pageNo); } }, tickTime); this.$once('hook:beforeDestroy', () => { // 通过这样监听! clearInterval(timmer); }); }
    ... ... // if结束后 的其他代码省略 }

    对比一下,内聚后的代码是不是逻辑更好理解了呢 ?

  • 相关阅读:
    选择高性能NoSQL数据库的5个步骤
    如何将 Redis 用于微服务通信的事件存储
    让你的AI模型尽可能的靠近数据源
    Collections.sort 给集合排序
    Bootstrap 文件上传插件File Input的使用
    select2 api参数的文档
    textarea 标签换行及靠左
    JSON
    JDK的get请求方式
    通讯录作业
  • 原文地址:https://www.cnblogs.com/zhwc-5w4/p/13235867.html
Copyright © 2020-2023  润新知