一、技术债务
因为早期的技术设计和妥协(鄙人猜测),需要前端侧在接口调用处理时兼顾两层code码的判断,导致前端项目中既有一层code码又有两层code码的处理,形成了编码思想上的不统一,会对继任的开发者造成极大困扰(什么时候是一层code码,什么时候又是两层code码?)。为了统一编码思想和偿还技术债务,需前端侧与应用层服务端、网关侧合力开发解决这个问题。
当回事后诸葛亮,若是早期的开发者能够前瞻假设下或坚持己见就不会有今天这档事;虽然有些问题可以在前端很容易处理掉,但是也的思考下这么做的代价。
二、设计方案
前端侧不参与是单层code结构还是双层code结构的逻辑计算,主要负责梳理接口结构、剥离双层code结构逻辑和完善接口调用的处理。网关侧针对社群业务增加相关逻辑,如果http响应头里有社群标识且响应体包含code信息就直接返回给前端侧。服务端负责在响应头上增加社群标识。
三、开发经历
-
调用的服务端接口很多,有没有统一的解决方案?
- 没有。前端侧没有针对双层code结构的中间层统一处理方式,所有的接口处理都在各自的页面组件里。
-
调用的接口又多,又没有统一的解决方案,那该怎么办呢?
- 凉办。梳理统计所有的业务板块,然后按人头分配下去,人肉去甄别处理。有时笨办法就是最有效的办法。
-
为了不影响正在测试的需求,代码不能暂时不能部署到sit环境,怎么办呢?
- 网关和服务端代码部署到dev环境。
-
dev环境数据不全,不便调试验证,还得部署到sit环境,怎么办呢?
- 网关和服务端代码部署到sit环境。
-
万一来了紧急需求,测试需要在sit环境验证,怎么办呢?
- 部署原来网关和服务端代码部署到sit环境。
-
来来回回部署网关和服务端代码部署到sit环境,是不是有点儿难为兄弟们了?
- 加开关。据设计方案可知,是返回单层code结构还是双层code结构是有社群服务端控制的,故可以加个开关切回原来的逻辑。
-
治理后的接口返回的数据较之前返回了多个值为
null的无用数据,是怎么回事呢?- 网关序列化问题。之前网关包装服务端接口时会进行序列化处理,序列化会把null的字段去掉。
-
治理后的接口返回异常code码(非0或非200)时出现了两个toast提示,是什么情况?
- 在接口响应层有一处封装,当code码非0或非200时会抛出个错误异常,该异常会被Promise的catch方法捕获并在此做了次toast提示然后
return false返回,下游业务应用层接着消费这个Promise.resolve(false)Promise再次做了toast提示。
- 在接口响应层有一处封装,当code码非0或非200时会抛出个错误异常,该异常会被Promise的catch方法捕获并在此做了次toast提示然后
-
那之前为什么不曾出现两次的toast提示呢?
- 运气好。因为之前网关侧做了一层包装且很少返回异常code码,基本上不会抛出异常触发Promise的catch方法,相关的toast提示都在业务层完成。
-
有没有什么办法可以试着屏蔽(或保留)一层toast提示呢?
- 没有。删除catch方法的toast提示?不行,下游有的业务层利用抛异常的方式来弹toast提示,不能直接删;catch方法返回
Promise.reject()让下游业务不走.then方法来阻断业务层的toast提示?不行,下游业务层没有对异常进行兜底处理是要报错的。
- 没有。删除catch方法的toast提示?不行,下游有的业务层利用抛异常的方式来弹toast提示,不能直接删;catch方法返回
-
到底怎么办才能保留一层toast提示呢?
- 头疼医头脚疼医脚。哪里有问题解决哪里的问题,莫要为了解决该问题引入其他问题。
-
万一项目上线后出现问题怎么办呢?
- 前端立即回滚,后端立即回滚或打开对应的开关;如此可以较少对网关的依赖。
- 利用测试环境观察时间,大家在测试环境充分验证。
四、温故知新
-
1.1 以为
.catch(failureCallback)是个特殊的方法,其实它等价于.then(null, failureCallback)。
1.2 以为已经settled的promise再调用.catch()或.then()方法不会执行,其实它会执行。
1.3 以为promise的任务编排只能这样.then().then().catch(),其实它可以这样Promise.reject('oops!') .then(null, res => { console.log(res); return 'yes!'; }) .finally(() => { console.log('finally'); throw 'no!' }) .catch(err => { console.log(err, 'error'); }) .then(res => { console.log(res, 'last-then'); }) .finally(() => { console.log('last-finally'); }) .catch(err => { console.log(err, 'last-err'); }); const promiseA = new Promise((resolutionFunc, rejectionFunc) => { resolutionFunc(777); }); promiseA.then((val) => { console.log("asynchronous logging has val:", val); return 12; }).then(res=>{ console.log(res); }); promiseA.then((val) => console.log("asynchronous logging has val:", val)); console.log("immediate logging"); // produces output in this order: // immediate logging // asynchronous logging has val: 777 // 121.4 promise的.then中回调函数具体的返回值依据以下规则返回: > - 返回了一个值,那么
then返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。 > - 没有返回任何值,那么then返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为undefined。 > - 抛出一个错误,那么then返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。 > - 返回一个已经是接受状态的 Promise,那么then返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的 Promise 的接受状态回调函数的参数值。 > - 返回一个已经是拒绝状态的 Promise,那么then返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的 Promise 的拒绝状态回调函数的参数值。 > - 返回一个未定状态(pending)的 Promise,那么then返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。 -
不要试图使用统一处理的思想处理那些不统一的事物,让它们待在各自该待的地方就好。
以上代码试图通过抛出异常来触发promise的.catch中回调函数来达成统一处理错误信息提示的功能,给后来code码治理带来了极大困扰。
五、其他优化
- 编码过程中,修复了一部分TS类型错误问题。
- 调整了webpack打包方式,对chunks包进行了瘦身。