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变量,实际是在交流如何去优化类似这种代码内部的顽疾。内部的优化往往不显山露水,属于只可在程序猿之间意会的内容。最后,再聊两点:
优化的时机
新功能迭代的开始或者旧功能的改造是相对较为恰当的时间点。一段比较稳定的开发时间是修改这些顽疾必不可少的条件之一。反之处理故障不是一个顺手修改的好时机选择。而一个暂时没有新迭代产生的项目,你也很难说服上级给你时间去进行这种内部的优化。
顺势而为,不要给自己徒增烦恼。
优化的人
优化前,有必要判断一下:自己是否真的是那个天命之人。
刚接手项目,贸然出手 ,容易翻车。刚加入公司,改故障做业务无疑更能站稳脚跟。对于经手项目较长时间,能在组里说得上话的你来说,干这些内部的优化无可厚非,自然老板或者上级也信任你,愿意给你时间。
还是那句话:
又水了一篇,完成这周预定的1/3,明天就是周末了。看来还得赶一赶。致敬每一位尚在屎山中挣扎的小伙伴。
更多内容可关注
我的公众号悬空八只脚