VUE实践优化:轮询机制与代码结构升级

2023-12-19

前言

我们之前探讨过,对于包含处理状态的表格数据,我们可以通过轮询的方式进行处理( 轮询更新进度条:JavaScript中的定时器和异步编程技巧 )。然而,当我们离开页面时,定时器仍会继续触发请求,这会造成资源的浪费,因为返回的数据并没有被渲染出来。

为了解决这个问题,我们需要实现以下要求:

  1. 最多只能同时存在一个轮询的定时器。
  2. 当用户离开页面时,定时器应被关闭。
  3. 当用户重新进入页面时,如果仍有数据正在处理中,应重新启动轮询。
  4. 轮询应能跨页面、跨显示数量。

实现

为了实现上述要求,我们可以采取以下步骤:

  1. 在全局范围内定义一个唯一的定时器变量,例如 running_task_timer
  2. 在开始轮询之前,检查 running_task_timer 是否已存在。如果存在,则清除该定时器并停止轮询。
  3. 如果需要启动轮询,首先检查页面是否处于激活状态。如果不在激活状态,则不启动轮询。
  4. 启动轮询时,设置 running_task_timer 为定时器的ID,并开始轮询处理。
  5. 当用户离开页面时,清除 running_task_timer 并停止轮询。
  6. 当用户重新进入页面时,检查是否有正在处理的数据。如果有,则重新设置 running_task_timer 并启动轮询。
  7. 在轮询处理中,检查页面是否处于激活状态。如果不在激活状态,则暂停轮询处理。
  8. 在轮询处理完成时,检查是否有新的数据需要处理。如果有,则重新设置 running_task_timer 并启动轮询。
  9. 通过上述步骤,我们可以确保同时只有一个轮询的定时器存在,并在用户离开页面时关闭定时器。当用户重新进入页面时,如果仍有数据正在处理中,可以重新启动轮询。同时,轮询的处理可以跨页面、跨显示数量进行。
<template>
  <div>
    <el-table :data="tableData">
      <el-table-column prop="id" label="任务ID" />
      <el-table-column prop="name" label="任务名称" />
      <el-table-column prop="status" label="任务状态" />
      <el-table-column label="操作">
        <template slot-scope="scope">
          <el-button @click="reloadTask(scope.row)">重新执行</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
export default {
  data() {
    return {
      tableData: [],
      running_task_timer: null,
      running_task_list: [],
    };
  },
  created() {
    this.getData();
  },
  beforeDestroy() {
    this.clearMyInterval();
  },
  methods: {
    getData() {
      axios
        .get(url, query)
        .then(res => {
          if (res.status === 200) {
            tableData = res.data.data;
            this.addRunningTask();
          }
        })
        .catch(error => alert(error));
    },

    addRunningTask() {
      this.running_task_list = [];
      this.tableData.forEach(item => {
        if (item.status === 'RUNNING') this.running_task_list.push(item);
      });
      this.running_task_list.length ? this.startInterval() : this.clearMyInterval();
    },

    startInterval() {
      const _this = this;
      this.clearMyInterval();
      this.running_task_timer = setInterval(() => _this.getData, 1000);
    },

    clearMyInterval() {
      if (this.running_task_timer !== null) clearInterval(this.running_task_timer);
    },

    reloadTask(row) {
      row.status = 'BEGIN';
      axios
        .put(url, { id: row.id })
        .then(res => {
          if (res.status === 200) this.getData();
        })
        .catch(err => {
          alert(err);
          row.status = 'DONE';
        });
    },
  },
};
</script>

数据定义

  • tableData : 这是一个数组,用于存储从服务器获取的表格数据。
  • running_task_timer : 这是一个定时器变量,用于轮询正在运行的任务。
  • running_task_list : 这是一个数组,用于存储状态为“RUNNING”的任务。

生命周期钩子

  • created() : 当组件被创建时,它调用 getData() 方法来获取数据。
  • beforeDestroy() : 当组件即将被销毁时,它调用 clearMyInterval() 方法来清除定时器,以避免资源浪费。

方法

  • getData() : 使用 axios 发送 GET 请求来获取数据。如果响应的状态码是 200,它将更新 tableData 并调用 addRunningTask() 方法。
  • addRunningTask() : 遍历 tableData ,找出状态为“RUNNING”的任务,并将它们存储在 running_task_list 中。如果 running_task_list 有内容,则调用 startInterval() 方法来启动定时器;否则,调用 clearMyInterval() 方法清除定时器。
  • startInterval() : 首先调用 clearMyInterval() 来清除可能已经存在的定时器,然后设置一个新的定时器,每隔1秒调用 getData() 方法来轮询数据。
  • clearMyInterval() : 如果 running_task_timer 不为 null,则清除该定时器。
  • reloadTask(row) : 更新特定行的状态为“BEGIN”,并使用 axios 发送 PUT 请求来重新加载任务。如果响应的状态码是 200,则再次调用 getData() 方法。如果请求失败,它会将行的状态设置为“DONE”。

改进

提升性能:只更新修改项数据

<script>
export default {
  data() {
    return {
      tableData: [],
      running_task_timer: null,
      running_task_list: [],
    };
  },
  created() {
    this.getData();
  },
  beforeDestroy() {
    this.clearMyInterval();
  },
  methods: {
    getData() {
      axios
        .get(url, query)
        .then(res => {
          if (res.status === 200) {
            tableData = res.data.data;
            this.addRunningTask();
          }
        })
        .catch(error => alert(error));
    },

    addRunningTask() {
      this.running_task_list = [];
      this.tableData.forEach(item => {
        if (item.status === 'RUNNING') this.running_task_list.push(item);
      });
      if (this.running_task_list.length > 0) this.startInterval();
    },

    startInterval() {
      const _this = this;
      this.clearMyInterval();
      this.running_task_timer = setInterval(() => _this.updateTask, 1000);
    },

    clearMyInterval() {
      if (this.running_task_timer !== null) clearInterval(this.running_task_timer);
    },

    updateTask() {
      if (this.running_task_list.length === 0) this.clearMyInterval();
      const queryIds = [];
      this.running_task_list.forEach(item => queryIds.push(item.id));
      axios.get(url, { params: { ids: queryIds } }).then(res => {
        if (res.status === 200) {
          res.data.data.forEach(update_item => {
            this.running_task_list.forEach(item => {
              if (update_item.id === item.id) item = { ...update_item };
              // 去除已经完成的任务
              if (item.status !== 'RUNNING') this.running_task_list.splice(this.running_task_list.indexOf(item), 1);
            });
          });
        }
      });
    },

    reloadTask(row) {
      row.status = 'BEGIN';
      axios
        .put(url, { id: row.id })
        .then(res => {
          if (res.status === 200) this.getData();
        })
        .catch(err => {
          alert(err);
          row.status = 'DONE';
        });
    },
  },
};
</script>

更新机制的改进 :之前的代码可能存在一个性能问题,即定时器会不断轮询服务器,无论运行的条数多少,都会全量更新接口返回的数据,这可能导致不必要的性能浪费。在新的代码中,我们通过在 updateTask 方法中只更新 running_task_list 中存储的需要更新的项,来避免了这一问题。任务完成后,从 running_task_list 中移除,从而在当前页更新完毕后停止轮询。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VUE实践优化:轮询机制与代码结构升级 的相关文章

  • 是否可以在没有 Javascript(仅 CSS)的情况下执行相同的操作(悬停效果)?

    我正在尝试创建一个带有图标的按钮像这样 http jsfiddle net pRdMc HTML div div class icon div span Send Email span div CSS button width 270px
  • 使用 npm 作为构建工具连接文件

    我最近发现我可以使用 npm 作为任务运行程序 而不是 gulp 或 grunt 到目前为止 一切都很棒 lint stylus jade uglify watch 等 但串联部分 我似乎无法实现 gulp 是这样的 gulp task s
  • jQuery UI sortable 和 contenteditable=true 不能一起工作

    我正在创建一个列表并希望使其项目可排序和可编辑 所以我这样做 ul li span A span li li span B span li li span C span li ul ul list sortable http jsfiddl
  • 如果浏览器在 asp .net 中关闭,请从浏览器中注销?

    我的要求有点复杂 用户正在使用 Web 浏览器访问数据库 而在访问数据库时 如果用户关闭活动页面而不是注销会话 该会话需要自动注销 有人可以指导我如何做这个吗 我在母版页中使用了jquery onbeforeunload 我收到消息离开页面
  • Google Charts(AreaChart)如何检测缩放变化

    我正在画一个面积图 在覆盖层上有一些标记 我正在使用explorer选项 仅限水平 以便用户放大和缩小 问题是我找不到一种方法来通知缩放更改 以便有机会更新制造商位置 有一个图表范围变化事件 但它不是由 AreaChart 触发的 我尝试检
  • 如何在提交表单之前删除自动数字格式?

    我正在使用 jQuery 插件自动数字 http www decorplanit com plugin 但是当我提交表单时 我无法删除之前字段上的格式POST 我尝试使用 input autonumeric destroy 和其他方法 但它
  • 光滑的旋转木马不工作

    我一直在尝试简单地实现 Slick Carousel 的工作 我已按照 Git 页面上的说明进行操作 https github com kenwheeler slick https github com kenwheeler slick 这
  • TRACKER:错误TRK0005:无法找到:“CL.exe”。该系统找不到指定的文件

    我尝试在 Windows 8 上的 Node js 项目中执行以下命令 npm 安装 电子邮件受保护 cdn cgi l email protection 但我收到一个错误 我不知道如何处理 TRACKER 错误TRK0005 无法找到 C
  • JavaScript:从 JavaScript 调用锚标记的点击事件

    我有一个带有锚标记的页面 在我的 JavaScript 中 我设置HREF锚标记的属性基于一些 if else 条件动态变化 现在我想以编程方式调用锚标记的单击事件 我使用了下面的代码 但没有成功 var proxyImgSrc CostM
  • 更新 Google 地图流量层而无需重新加载页面

    我的页面中嵌入了 Google 地图 我使用 initMap js 函数来初始化地图 function initMap var map new google maps Map document getElementById t map zo
  • 如何将函数传递给 JavaScript Web Worker

    我想通过一个 或多个 函数传递postMessage 给网络工作者 因为我无法引用常规文件 为了启动 Web Worker 我将一个对象 URL 从 Blob 创建 传递给Worker构造函数 然后我传递一条消息 但到目前为止还没有在消息中
  • 如何检查元素的内容是否为空,如果是,则在 jquery 中删除该元素

    我目前正在尝试选择某个 div 内没有内容的任何 h2 元素并将其删除 这是我的 html 代码 div class skipToContainer h2 class vidSkipTo Hello h2 h2 class vidSkipT
  • 在 HTML5 中将两个图像合并到一个画布上

    我正在使用 HTML5 canvas 元素 假设我有 2 个 ImageData 对象 我想将它们组合起来放在一张画布上 假设我不关心这些图像如何组合 两个 ImageData 对象具有完全相同的像素数和形状 组合两个图像的最佳方式是什么
  • 在 jQuery AJAX 成功中从 MySql 获取特定响应

    好吧 我有这个 ajax 代码 它将在 Success 块中返回 MySql 的结果 ajax type POST url index php success function data alert data My Query sql SE
  • (0, eval) () 的作用是什么? [复制]

    这个问题在这里已经有答案了 以下内容来自这个问题 https stackoverflow com questions 14119988 return this 0 evalthis 14120023 14120023 function q
  • ReferenceError 和全局对象

    在浏览器中的 JavaScript 中window是全局对象 这意味着在全局范围内定义的每个变量都是window 那么为什么我会得到这个结果 console log window foo No error logs undefined co
  • PhantomJS 网页内存消耗?

    是否有一种编程方式 因为我想在运行时自动执行 方式来查看网页在通过 PhantomJs 运行时使用了多少内存 我也在使用 casperjs 如果这有帮助的话 我已经搜索了很多但没有找到任何方法 PhantomJs 使用 QtWebKit 因
  • 显示班级图片 10 秒

    我有下面给出的代码显示9 boxes 其值如下digital time 还有一个班级box002显示digits相当于随机选择的九个盒子的值 box002 can be dragged to digital time starting wi
  • JavaScript 中最长的通用前缀

    我正在尝试解决 Leet Code 挑战14 最长公共前缀 https leetcode com problems longest common prefix 编写一个函数来查找字符串数组中最长的公共前缀字符串 如果没有公共前缀 则返回空字
  • 使用 JavaScript onclick 添加表格行

    我正在尝试使用 javascript 添加下面找到的完全相同的元素 我已经尝试了这里找到的所有解决方案 我什至尝试用php echo但没有运气 无需更改任何输入名称或类似内容 只需单击该按钮即可向表中添加另一行 仅此而已 这是该元素 tr

随机推荐