React-Native开发鸿蒙NEXT-从global变量聊聊代码的内部优化

178 阅读7分钟

React-Native开发鸿蒙NEXT-从global变量聊聊代码的内部优化

原创 悬空八只脚 悬空八只脚 2024年11月07日 21:22 江苏

又到了瞎编点技术帖的时候,很难。题目是上周立的,正文是现在开始写的。早上十点,今天起晚了刚买菜回来,把排骨放水池里泡着,坐下来开始瞎编。

现在是晚上9点,继续来编吧,争取明天能发布。global变量是RN中实现全局变量的一种方式。利用global.xxx可以方便地完成全局传递诸如接口请求配置、临时缓存数据等操作。凡事有利也有弊,global变量的肆意滥用对项目会造成不可想象的协作问题。这些天在将社区RN调整适配HarmonyOS Next,说是适配其实是在重构,自然哪哪感觉有问题都会走走看看。随便搜了下项目中global的使用。

图片

屎山不是一天堆成的。多年的项目,历经多任开发维护后,积攒的量是相当惊人的。更惊人的是:在项目维护的过程中,负责故障修复的小伙伴并不会关注看前任们留下的编码习惯,一番敲敲打打继续上路,无形中又将这种原有的滥用问题进一步扩大。以至于后续开始陆续出现诸如if(global.id || global.Id || global.targetId || global.target_id)之类的无奈判断。

剪不断,理还乱。想要出人头地?先问问绩效答不答应。

以下是一些基于过去项目经验之上的这类问题的优化建议。

优先隔离问题,无论隔离的方法是否是最优解。

优先区分敌我,把问题隔离,不要让问题进一步扩大恶化。冰冻三尺,非一日之寒,代码中的顽疾绝非简单的什么个人习惯问题。面对错综复杂的局势,优先找出一种有效的隔离方法,将问题或替代,或包裹,不追求最优,只为快刀斩乱麻。以项目中的global变量为例,大量且滥用的global变量,根据对项目掌握的经验,大致区分成三大类:1.RN启动时传入的初始化参数 2.初始参数中的一份配置信息,这部分因为用的地方较多可能需要单独抽出 3.在运行中少数需要全局临时缓存的数据。针对现状,简单封装几个方法。大致的逻辑是config和initParam只读,运行中设置的custom可读可写

function configExist() {
    return !!global && !!global.config;
  }
  
  function configKeyExist(key: string) {
    if (configExist()) {
      return (key in global.config);
    }
    return false;
  }
  
  function initParamExist() {
    return !!global && !!global.initParam;
  }
  
  function initParamKeyExist(key: string) {
    if (initParamExist()) {
      // xLog(' nitParamExist() key = ' + key);
      // xLog(' global.initParam = ' + JSON.stringify(global.initParam));
      return (key in global.initParam);
    }
    return false;
  }
  
  function customExist() {
    return !!global && !!global.custom;
  }
  
  function customKeyExist(key: string) {
    if (customExist()) {
      return (key in global.custom);
    }
    return false;
  }
  
  function getConfig() {
    if (configExist()) {
      return global.config;
    }
    return null;
  }
  
  function getConfigByKey(key: string) {
    if (configKeyExist(key)) {
      return global.config[key];
    }
    return null;
  }
  
  function getInitParam() {
    if (initParamExist()) {
      return global.initParam;
    }
    return null;
  }
  
  function getInitParamByKey(key: string) {
    if (initParamKeyExist(key)) {
      return global.initParam[key];
    }
    return null;
  }
  
  function clearInitParam() {
    if (initParamExist()) {
      global.initParam = {};
    }
  }
  
  function setCustom(key: string, value: any) {
    if (!global.custom) {
      global.custom = {};
    }
    global.custom[key] = value;
  }
  
  function getCustom() {
    if (customExist()) {
      return global.custom;
    }
    return null;
  }
  
  function getCustomByKey(key: string) {
    if (customKeyExist(key)) {
      return global.custom[key];
    }
    return null;
  }
  
  const xnUtils = {
  。。。。。。
    configExist: configExist,
    configKeyExist: configExist,
    getConfig: getConfig,
    getConfigByKey: getConfigByKey,
    initParamExist: initParamExist,
    initParamKeyExist: initParamKeyExist,
    getInitParam: getInitParam,
    getInitParamByKey: getInitParamByKey,
    clearInitParam: clearInitParam,
    customExist: customExist,
    customKeyExist: customKeyExist,
    getCustom: getCustom,
    getCustomByKey: getCustomByKey,
    setCustom: setCustom,
  };
  export default xnUtils;

完全是粗暴的屏蔽直接使用global,没有彻底解决问题,但将现有代码简单分为"已处理"和"未处理"两部分,在不影响现有业务的情况下进行逐步替代。后续再针对新加入的方法进一步考虑。

万事开头难,走出第一步是最重要的。

根据实际进行评估,确定实际工作量与难度。

评估工作量和工作难度是工作中重要的一环。如何有效评估?建议选择一个现有的功能模块,或者即将开发的新功能,以"彻底替代"为基准进行实际操作,一次评估。这里着重强调的是"彻底"。项目中一个功能模块往往能牵扯出一堆公共类,帮助类这些基础功能结构,在评估的时候按照是否功能模块使用为基准来针对应做替代。往往这部分公共类里包含的工作量在评估的时候是最容易被忽视的,这是容易造成评估时间不足的最大原因。越是古老的项目,积累起来的这种公共类越是盘根错节。

HomeTab.tsx(tab标签-首页)

......
  //处理外界直接指定跳转
  const goToPage = () => {
    xLog(TAG + ' 进入goToPage!');
    //  absolutePage 表示这是一个绝对页面跳转而不是之前的跳转到详情,absolutePage定义了跳转页面的名字
    if (xnUtils.initParamKeyExist('absolutePage')) {
      xLog(TAG + ' [goToPage] ' + ' absolutePage = ' + xnUtils.getInitParamByKey('absolutePage'));
      // 跳转
      navigation.push(xnUtils.getInitParamByKey('absolutePage'), xnUtils.getInitParam());
      xnUtils.clearInitParam();
      return;
    }
......

HomeRecommend.tsx(tab标签-首页中显示推荐内容的部分)

......
/**
 * 获取社区广告列表
 */
const getForumAdDataList = () => {
  let params = {
    sourceFrom: 'APP',
    tenantId: xnUtils.getCustomByKey('tenantId'),
    forumId: xnUtils.getConfigByKey('forumId'),
    searchType: 'HAS_PUBLISH',
    // cityCode: this.props.cityCode,
    isActive: true,
  };
  ......

NavHeader.tsx(推荐类表中用于显示帖子头像的小组件)

AppService.getPassportByUnionTenant(params)
.then(data => {
  setLoading(false);
  if (data.errFlag) {
    xnToast(data.errMsg);
    return;
  }
  xnUtils.setCustom('tenantId', data.passport.tenantId);

没有调查,就没有发言权。

过程中经常回顾,是否有新的理解。

凡事皆有代价。先下手为强的代价就是对于处理方式需要经常复盘。

抛弃global,改用rudex之类来处理是否是一种更好的选择?

如何在开发过程中去约束这种随意起变量的行为?

开发个插件来辅助处理这些全局变量?

只要在路上,总有到达的一天。

形成文档输出。

如果文档只是用来衡量工作量,那大可不必这么事必躬亲。外行看热闹,内行看门道,把文档看做是对下一任交代的方式。自己经手时间较长的项目一般都会留个readme,或者todo,一句话交代一件事,如"某某时间针对某某问题做了某某调整,具体见wiki某某某"。如果一件事情值得去做,那就值得将这件事情记录下来,告诉后来者曾经走过的路。

我不是在教你做事,我只是在教你如何早点下班。

瞎扯了这么多,看似在聊怎么去优化满屏飞的global变量,实际是在交流如何去优化类似这种代码内部的顽疾。内部的优化往往不显山露水,属于只可在程序猿之间意会的内容。最后,再聊两点:

优化的时机

新功能迭代的开始或者旧功能的改造是相对较为恰当的时间点。一段比较稳定的开发时间是修改这些顽疾必不可少的条件之一。反之处理故障不是一个顺手修改的好时机选择。而一个暂时没有新迭代产生的项目,你也很难说服上级给你时间去进行这种内部的优化。

顺势而为,不要给自己徒增烦恼。

优化的人

优化前,有必要判断一下:自己是否真的是那个天命之人。

刚接手项目,贸然出手 ,容易翻车。刚加入公司,改故障做业务无疑更能站稳脚跟。对于经手项目较长时间,能在组里说得上话的你来说,干这些内部的优化无可厚非,自然老板或者上级也信任你,愿意给你时间。

还是那句话:

u=3060479155,3748861711&fm=253&fmt=auto&app=138&f=JPEG.webp

又水了一篇,完成这周预定的1/3,明天就是周末了。看来还得赶一赶。致敬每一位尚在屎山中挣扎的小伙伴。


更多内容可关注
我的公众号悬空八只脚