你小子,一个bug排查一整天,你在🐟吧!

楔子

  在每日的例行会议上,空气中弥漫着紧张的气息。一位实习组员语速略急地说道:“昨天我主要的工作是排查一个线上bug,目前还没有得到解决,今天我得继续排查。”。

  组长眉头微皱,冷冷地盯了他一眼:“你小子,一个bug排查一整天,怕是在摸鱼吧!到底是什么问题?说来听听,我稍后看看。”。

  组员无奈地摊了摊手,耸了耸肩,长叹一口气:“前两天,订单表格新增定制信息匹配失败情况的展示。自己没有经过仔细的测试,就直接发布上线了,导致现在整个订单列表渲染缓慢。这个bug超出了我的能力范围,我排查了一天也排查不出来,摸鱼是404的。”。

  组长深吸一口气,眼神中露出几分聪慧:“那不就是你编写的组件有问题吗?你最好没有摸鱼!不然你就等着吃鱼吧!”。

  组员按捺不住心中的窃喜:“我如果不说一天,又怎么能请动你这尊大神呢?”。

你小子.jpg

排查

  果不其然,控制台果真报错了。组长看了眼报错信息,摇了摇头,面色凝重:“你小子,居然都不看控制台的报错信息?这bug怎么排查的?”。组员下意识地捏紧了拳头,声音也不自觉地低了几分,结结巴巴道:“我、我真的不知道控制台还有这操作!学废了。”。

image.png

  组长怀着忐忑不安的心情打开vsCode, 只见一大串代码赫然映入眼帘:

<template>
  <div class="design-wrapper">
    <designProducts v-if="showBtn" btnText="设计" class="mr10" :data="data" @success="success" />
    <el-tooltip v-if="showStatus" trigger="click" placement="right" :disabled="disabled">
      <baseTable1 class="hide-tabs" :data="tableData" :option="option">
        <template #content="{ row }">
          <defaultImg v-if="imageType(row)" :src="image(row)" :size="100" />
          <span v-else>{{ text(row) }}span>
        template>
        <template #mapping="{ row }">
          <i :class="icon(row)">i>
        template>
        <template #importLabelCode="{ row }">
          <span v-if="!row.hide">{{ row.importLabelCode }}span>
        template>
        <template #matchStatus="{ row }">
          {{ matchSuccess(row) ? '已匹配' : '未匹配' }}
        template>
        <template #design="{ row }">
          <defaultImg
            v-if="!row.hide && imageType(row)"
            :disabled="row.disabled"
            :src="row.importContent"
            :size="100"
            @error="error(row)"
          >
            <template #defaultImg>
              <div class="flex-middle">{{ row.importContent || '无' }}div>
            template>
          defaultImg>
          <div v-else-if="!row.hide && !imageType(row)">{{ row.importContent || '无' }}div>
        template>
      baseTable1>
      <color-text-btn slot="reference" @click="toDesign">{{ status }}color-text-btn>
    el-tooltip>
    <span v-else>span>
  div>
template>

  当扫到el-tooltip (文字提示), 组长拍案而起,额头上暴起的青筋在不断颤抖。急切的声音,仿佛要撕裂虚空:“你小子,短短几十行代码,至少犯了2个致命错误!”。

问题分析

1. 从代码源头分析el-tooltip(控制台报错的原因)

  • el-tooltip组件主要是针对文字提示,而el-popover才是针对组件进行展示。这两者是截然不同的,不然element也不会分出两套组件,去分别处理这两种情况。

  • 我们的项目之所以能正常使用vueXrouter,是因为我们在main.js中引入并挂载了

    QQ截图20241009142821.png

    同理,分析el-tooltip组件的代码实现,它只挂载了data属性。因此,当强行在el-tooltip组件中使用自定义组件:如果组件内部使用的是非国际语言(i18n)的纯文本,控制台不会报错;如果在该组件中使用了诸如vueX、路由跳转等在内的变量或者方法时,控制台就会疯狂报错,因为这些并没有在初始化时注入到el-tooltip组件中。

    image.png

2. 如何在el-tooltip中使用i18n?

  假定有一个非常执拗的人,他看到el-tooltip组件描述的功能是文字提示。他就不想在el-popover中使用$t, 而想在el-tooltip组件中使用i18n。那么可以做到吗?答案是肯定的。

  我们可以直接通过继承法则:封装一个base-tooltip组件,继承el-tooltip组件。并根据继承规则:先执行el-tooltip组件的生命周期钩子方法,再执行base-tooltip组件里面的生命周期钩子方法。通过这种方式,我们成功挂载了i18n。此时,在base-tooltip组件中使用$t,就不会报错了。


3. el-tooltip的局限性(订单列表渲染缓慢的原因)

  前文提及,我们可以继承el-tooltip组件。那么,我们如果通过按需引入的方式,将所需要的资源全部挂载到vue中。这样,就算在base-tooltip组件中使用vueX$route变量,也不会在控制台上报错。的确如此,但是我们需要注意到el-tooltipel-popover的局限性: 悬浮框内容是直接渲染的,不是等你打开悬浮框才渲染。

  这也就意味着,如果我们在表格的每一行都应用了el-tooltipel-popover组件,而且在el-tooltipel-popover的生命周期钩子函数中请求了异步数据。就会导致页面初始化渲染数据的同时,会请求N个接口(其中,N为当前表格的数据条数)。一次性请求大于N + 1个接口,你就说页面会不会卡顿就完事了!

  但是,el-popover这个组件不一样。在它的组件内部,提供了一个show方法,这个方法在trigger触发后才执行。于是,我们可以在show方法中,去请求我们需要的异步数据。 同时注意一个优化点:在悬浮框打开之后,才渲染Popover内嵌的html文本,避免页面加载时就渲染数据。

  由于el-popover的内容是在弹窗打开后才异步加载的,弹窗可能会在内容完全加载之前就开始计算和渲染位置,导致弹出的位置不对。但是我们遇到事情不要慌,el-popover组件的混入中提供了一个方法updatePopper,用于矫正popover的偏移量,以期获取正确的popover布局。

image.png

解决方法

  将上述所有思路结合在一起,我们就能够封装一个公共组件,兼容工作中的大多数场景。



<script>
import agentMixin from '@/mixins/component/agentMixin'

export default {
  
  mixins: [agentMixin({ ref: 'popover', methods: ['updatePopper', 'doClose'] })],
  
  props: {
     
     beforeOpen: Function
  },

  data() {
    return {
      isOpened: false
    }
  },
  
  methods: {
    async onShow() {
      if(!this.beforeOpen) {
        return this.isOpened = true
      }
      const res = await this.beforeOpen()
      if(!res) return this.isOpened = false
      this.isOpened = true
      await this.$nextTick()
      this.updatePopper()
    }
  }
}
script>


import { isArray, isPlainObject } from 'lodash'

export default function ({ ref, methods } = {}) {
  if (isArray(methods)) {
    methods = methods.map(name => [name, name])
    
  } else if (isPlainObject(methods)) {
    methods = Object.entries(methods)
  }
  
  return {
    methods: {
      ...methods.reduce((prev, [name, alias]) => {
        prev[alias] = function (...args) {
          return this.$refs[ref][name](...args)
        }
        return prev
      }, {})
    }
  }
}


<script>
methods: {
    async beforeOpen() {
      const res = await awaitResolveDetailLoading(
        microApi.getMatchInfo({
          id: this.data.id
        })
      )
      if (!res) return false
      this.tableData = res
      return true
    }
}
script>

反思

  在组长的悉心指导下,组员逐渐揭开了问题的真相。回想起自己在面对bug时的轻率和慌乱,他不禁感到一阵羞愧。组长平静而富有耐心的声音再次在耳边响起:“排查问题并非一朝一夕之功。急于上线而忽视测试,只会让问题愈加复杂。”这一番话如同醍醐灌顶,瞬间点醒了他,意识到自己的错误不仅在于代码的疏漏,更在于对整个工作流程的轻视。

  “编写代码不是一场竞赛,速度永远无法替代质量。”组长边调试代码,边语重心长地说道。组长的语气虽然平淡,却蕴含着深邃的力量。组员心中的敬佩之意油然而生,细细回味着这番话,顿时明白了面对复杂bug时,耐心与细致才是解决问题的最强利器。组长的话语简洁而富有哲理,令他意识到,曾经追求的“快速上线”与开发中的严谨要求完全背道而驰。

  不久之后,组员陷入了沉思,轻声开口:“起初,我还真觉得自己运气不好,偏偏遇上如此棘手的bug。但现在看来,这更像是一场深刻的教训。若能在上线前认真测试,这个问题本是可以避免的。”他的声音中透出几分懊悔,眼中闪烁着反思的光芒。

  组长微微一笑,点头示意:“每一个bug都是一次学习的契机,能意识到问题的根源,已是进步。”他稍作停顿,眼神愈加坚定:“编程的速度固然重要,但若未经过深思熟虑的测试与分析,那无疑只是纸上谈兵。写代码不仅需要实现功能,更需要经得起时间的考验。”这番话语透着无可辩驳的真理,给予了组员莫大的启迪。

  组员感慨道:“今天的排查让我真正领悟到耐心与细致的重要性。排查bug就像走出迷宫,急躁只会迷失方向,而冷静思考才能找到出路。”他不禁回忆起自己曾经的粗心大意,心中暗自发誓,今后在每一次提交前都要更加谨慎,绝不再犯同样的错误。

  “你小子,倒也不算愚钝。”组长调侃道,嘴角勾起一丝轻松的笑意,“但记住,遇到问题时要先冷静分析错误信息,找出原因再行动。不要盲目修改,开发不仅仅是写代码,更需要学会深思熟虑。”他轻轻拍了拍组员的肩膀,那一拍似乎传达着无限的关心与期望。

  这一拍虽轻,却如雷霆般震动着组员的心灵。他明白,这不仅是组长对他的鼓励,更是一份期待与责任的传递。心中顿时涌起一股暖流,他暗自立誓:今后的每一次开发,必将怀揣严谨的态度,赋予每一行代码以深刻的责任感,而不再仅仅是为了完成任务。

  在回家的路上,组员默默在心中念道:“这次bug排查,不仅修复了代码,更矫正了我对待开发工作的态度。感谢组长,给予我如此宝贵的经验和鼓励。”他深知,从这次经历中所学到的,绝不仅是技术层面的知识,更需要以一种成熟与稳重的心态,来面对未来的每一个挑战。

  怀着这样的领悟,组员的内心充满了期待。他坚信,这必将成为他在开发道路上迈向更高境界的起点。

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=21394,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?