首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
321 阅读
2
如何在 Clash for Windows 上配置服务
216 阅读
3
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
150 阅读
4
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
149 阅读
5
uniapp打包app提示通讯录权限问题,如何取消通讯录权限
113 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,202
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
1202
篇与
的结果
2024-10-20
腾讯抢金达人项目中的前后端协作
在前后端的协作过程中,通常都是并行开发的状态,那么在后端接口还没有开发完毕时,前端的业务逻辑工作就很难展开。因此也就有很多模拟接口数据的方式,这些方式各有个的优缺点: 直接在代码中模拟接口数据:侵入业务逻辑,在后期需要删除这些模拟数据; fiddler 替换文件:页面接口比较多时,需要替换的文件比较多; fs 模块读取 json 文件:若是长列表的话,需要造的数据很多; mockjs:避免上述方式的缺点,但无法校验参数是否缺失; service worker:基于 service worker 可以拦截前端的请求,并构建假数据返回,但无法拦截 node 端发起的请求; 方式 校验参数合法性 切换环境方便 前后端请求均可 不修改业务代码 模拟数据方便 直接在业务代码中写接口数据 fiddler 替换文件 yes fs 读取 json 文件 yes yes mockjs yes yes yes sw yes 我们理想的状态是: 提前校验请求接口中参数的合法性,是否缺失某些参数等; 切换环境方便,既可以使用模拟数据,也可以使用测试环境中的数据,同时也可以用正式环境中的数据进行检验; 可以拦截前后端均发起的请求,并尽量少的修改业务代码; 生成的模拟数据方便,假如接口中要返回前 1000 名用户的数据,总不能在 json 文件中写 1000 条数据; 上面的这几种方式,在我们抢金达人项目中,均不适用,或者对原有逻辑改动太大,或者使用起来不方便。这里我根据我们项目的需要,基于 mockjs 并与 express 的结合,实现了一套模拟数据的方法。 1. 模拟数据并校验参数的合法性 # 把接口的数据全部写在 json 文件,然后通过 fs 模块进行读取的这种方式,在构造大量数据时非常不方便。因此我们基于 mockjs 来实现模拟的数据,几行代码就能实现排行榜等大量的模拟数据,同时,也可以模拟一些稍微极端的情况,例如用户的昵称长度过长等,这些数据在测试环境一般很少能遇到,或者在后端接口模拟的成本也会比较高。// rank-person.js Mock.mock({ "rank|1000": [ { "no|+1": 1, uin: () => Mock.Random.string(32), nick: () => Mock.Random.string(1, 20), face: () => faces[Mock.Random.integer(0, 3)], region: "INVALID", title: "初露锋芒", level: () => Mock.Random.integer(1, 20), score: () => Mock.Random.integer(1, 2000), winPercent: 86 } ] }); 但是,纯基于 mockjs 数据的方式,我们无法提现获知接口参数的异常。当我们在匹配到接口请求后就返回数据,会降低对参数的敏感度。这里,我对配置文件进行改造,当前接口中需要的参数提前设定好,类似于 jQuery.validate 中的设定。这里我们的排行榜接口里有个last参数,0 表示是本周的数据,1 表示是上周的数据:module.exports = { params: { last: { required: true, // 是否必须 type: "number", // 参数的类型 defaults: 0, // 默认值 min: 0, // 最小值 max: 1 // 最大值等 } } }; 当 mock server 接收到请求后,会先校验参数的合法性,若参数不合法直接返回。其实我们排行榜的 last 参数不是必传项,不传时即默认是 0,但我们在这里测试时改为必传,只要不传 last 参数即为参数不合法:当参数校验通过后,才会返回后面模拟的数据: 2. 数据环境的切换 # 我们在上面的图中可以看到,当 mock 字段为"mock"时,读取模拟的数据,是不是一定要加一个 mock="mock"的参数才能去读模拟的数据呢?这个要看咱们项目到什么状态了,当项目还在前提开发阶段时,大部分接口都还没有完成,这里我们可以将接口默认指向到模拟数据,mock="testing"时就指向到测试环境的接口;当项目已稳定上线了,在迭代更新的阶段时,大部分接口已经存在和完善了,只有部分的接口需要进行模拟调试,这时我们用mock="mock"参数来指向到模拟数据。这里我使用 mock 参数控制,还有一个原因是,前端项目会根据当前是哪个环境,自动请求对应环境的接口,所有的接口均是统一控制的:如上图所示,如果我们要通过环境变量控制 api 字段,最终强行修改某个接口变相请求其他环境的数据,会造成其他接口数据的混乱,最终可能的结果是页面整体会挂掉。我们在使用mock字段作为参数时,侵入的业务逻辑会维持到最小的程度,同时,也能把前后端的协作,缩小到单个接口的粒度。而且,mock 参数也只会在 local 环境生效,即使忘了去掉这个参数,也不会对线上环境造成影响。再有,当我们前端逻辑发生变化后,除了使用模拟数据来检验,如果线上有接口,我们也想用线上的数据检验一下。可以,当传入mock="production"的参数时,mockServer 会读取线上接口的数据并返回。 3. mock 与 json # 有的同学会创建一个 json 文件,把接口需要的数据都放到这个 json 文件里,然后使用fs.readFile来读取。这样倒是也可以,但是当接口数据多的时候怎么办,例如有一个排行榜是要输出前 100 名、前 1000 名用户的数据,总不能复制出 1000 份用户的数据吧。在当前最好的方式,就是使用 mockjs 的工具来生成数据了,可以任意的随机,也可以生成任意个数的数组数据。我们这里把对参数的校验和 mock 生成的模拟数据放到一起:module.exports = { params: { last: { required: true, // 是否必须 type: "number", // 参数的类型 defaults: 0, // 默认值 min: 0, // 最小值 max: 1 // 最大值等 } }, result: { code: 0, msg: "success", "x-from": "mock", data: Mock.mock({ "rank|100": [ { "no|+1": 1, uin: () => Mock.Random.string(32), nick: () => Mock.Random.string(1, 20), face: () => faces[Mock.Random.integer(0, 3)], region: "INVALID", title: "初露锋芒", level: () => Mock.Random.integer(1, 20), score: () => Mock.Random.integer(1, 2000), winPercent: 86 } ] }) } }; params 字段表示必须的参数,result 表示要返回的数据,data 中即为我们伪造的数据。 4. 实时修改模拟数据 # 我们可以在页面中直接实时修改数据,然后进行保存,自动刷新页面后,就会得到刚才想要的结果。我们在页面中 mock 的接口都会在调试面板中展出来,默认调试面板时关闭的,开发者在点击页面右下角的灰色按钮后,可以呼起调试面板。修改里面的数据保存后,就实时看到刚才的效果。 5. 总结 # 在开发和后期维护的过程中,前端会经常遇到模拟接口数据的情况,要么是接口还没有开发完成,要么是接口不太好返回我们想要的状态。我也是在对比多种方案后,选择了适合当前项目的一种前后端协作方案。
2024年10月20日
9 阅读
0 评论
0 点赞
2024-10-20
再见2019,你好2020
鼠年的春节已经过去了,然而在这时候却赶上了“新型冠状病毒肺炎”,全国几乎进入到了静止模式。没事儿的时候,上下一片祥和,有事儿的时候,各种妖魔鬼怪在人间。这里我也是对自己刚过去的 2019 年做下总结,整装待发开始 2020 年。 1. 工作 # 去年的一整年里,感觉一直在忙,上半年在忙红包中心和极速版的福利中心,也是在使用过 vue 后,首次尝试 react+typescript,其实我在 Vue 中就已经使用了 typescript,但 Vue 对 ts 的支持不是很好,在 react 中才发挥了更大的威力。下半年主要是在做抢金达人活动,为了减少首页加载的时间,我也进一步尝试了 nodejs 在项目中的使用,使用同构直出渲染方案来实现这个项目。在项目实现的过程中,我加深了对 nodejs 的认知,不再把它单单作为一个小工具来实现,可以来实现更多的功能。我们也通过自动构建工具,将我们的项目部署到 stke 上,实现了完全自动化的构建和部署流程。有着项目上线的期限,还有在实践 nodejs 过程中的一步步踩坑,同时还要准备晋级答辩。导致那段时间特别忙,博客的时间线上也出现了 3 个月的空白期。到 9 月份了,才开始了重新写博客。同时,在下半年,我也提升了自己的分享欲望,在还没有轮到我进行分享的时候,我就已经想好了好几个主题进行选择,不过因为分享机制的原因,最终也仅仅有 2 次的分享。从 12 月中旬到春节前的这段时间,也是特别地忙,一个人要同时支撑好几个项目的上线,同时其他项目还有零星的小需求要支持。最多的时候,同时有 4 个需求在排队等着,直到回家前一天的晚上,才把所有的项目进行收尾。在去年的一整年里,总共写了 28 篇博客文章,差不多相当于每两周 1 篇的频率。在新的一年里,期望能有更多分享的主题,争取能达到 40 篇的目标。 2. 生活 # 我们在 10 月份去了趟动物园,当时本来以为那天会很冷,周末开始忽然气温回升,阳光明媚,去动物园看了不少的动物。其实,我也是第一次看到真实的大熊猫。几年没去动物园,动物园现在在现场也可以扫码购票了,不用再排上长长的队伍。孩子着实是害怕那些大型动物,例如一些非洲象/亚洲象,老虎等,虽然隔着铁栅栏和玻璃窗,他们也是偷偷地看两眼后,想着赶紧离开这个地方。当时我的新年愿望是:在新的一年里不要加班,不要996,不要任何形式上的加班。没想到春节就发生了“新冠肺炎”这件事儿,还这么严重。为那些奋斗在一线的医护人员致敬。在读书这方面,确实很惭愧,经典的四大名著,我也是在2018年才看完《三国演义》,在2019年看了《西游记》,还剩下2本,争取今年能看完一本。 3. 总结 # 在新的一年里,希望自己能够更进一步。技术上,在nodejs、react等发发力,对里面深层次的东西,做更进一步的了解;生活上也能开开心心地每一天。 nodejs的加密模块/Buffer模块等; reactjs的diff原理/虚拟dom等; leetcode上的题目能够达到250道题(目前已157道题); 公众号的粉丝争取上1000; 编写一个简单的微信小程序; 其实很可惜地在2018年的年底没有写年终总结,今年怎么说也得给不上。年终总结不是任务,只是让自己总结去年的得失,能够在新的一年整装待发。
2024年10月20日
5 阅读
0 评论
0 点赞
2024-10-20
震惊!数据被删了,怎么办?
微盟这个公司的名声相信比之前大了很多,然而这并不是什么好的名声,而是运维人员删除了数据库中的所有数据。删库跑路本来是我们程序员调侃的一个梗,但若真因为公司惹你生气,删库跑路了,你也是要承受牢狱之灾的。 1. 微盟被删库 # 资料显示,微盟成立于 2013 年 4 月,有员工超 3200 人,渠道代理商超 1600 家,注册商户超 300 万。是中小企业云端商业及营销解决方案提供商,同时也是腾讯社交网络服务平台中小企业精准营销服务提供商。我们先来回顾下时间线: 2020.2.23 日 18:56,员工远程登入服务器并实施破坏。 2020.2.23 日 19 时,系统监控报告故障并启动应急方案。 2020.2.24 日 微盟公司向警方报案。 2020.2.25 日 7 时,恢复部分生产环境和数据,并预计到凌晨 0 点能完成恢复,并向新用户恢复业务,但老用户预计还要到 2 月 28 日晚上才能恢复。 目前来看,老用户的数据恢复依然比较困难,就看微盟数据的备份情况了。不过就微盟而言,这一次也不会倒下的。同时,这已经不是第一次删库跑路的情况了。2018 年 9 月,顺丰工程师手误删除线上系统的一个库; 2018 年 6 月初,前任管理人员删光其公司云主机厂商的所有客户数据; 2017 年 3 月,因不满被公司辞退,使用定时脚本每日执行删除操作,造成今麦郎的终端管理系统瘫痪; 2017 年 2 月,荷兰的数据库管理在数据库复制过程中,意外地删除了一个目录,导致 300GB 的生产数据丢失,并无法恢复。 2. 员工对公司的不满 # 大部分删库的情况,都是员工不满公司对自己的态度,比如疯狂加班、辞退没有补偿、想加薪被拒绝等等。然而,对公司的不满,并不能成为你删库跑路报复公司的原因。若公司对你不公,你可以申请仲裁,或者去法院告它。虽说流程长点,但这才是你保障自身权益的合法手段。删库跑路时虽然很爽,但你也终究是逃脱不了法律的制裁。有的人觉得写个定时脚本,在自己离职后,脚本才删除数据,然后再删除自己。可是,只要你做了这件事儿,必然会留下痕迹的,不要想着能干干净净地跑路。还有就是无意操作导致的,比如在数据迁移过程中没有做好备份和回滚,导致中间出错后,无法恢复数据。这种就是属于操作不规范。 3. 如何防范被删库 # 很多删库的行为,其实是可以避免的。 3.1 对员工的关怀 # 大部分删除跑路都是因为员工对公司不满,这里也提倡公司能够对员工的身心更加关心一些,即使员工要离职了,也是能够感谢在公司的这段岁月没,而不是心里一直怨恨公司。我也是跳过两次槽,但都是好聚好散。无论是员工自己、还是公司,都建议能够互相体谅。毕竟公司的体量更大,也有很多的法务和hr是专门负责这些事情,员工对公司而言仅仅是个小小的职员,但公司却也是员工维持生计仅有的选择。 3.2 权限 # 有的小公司在人手不够时,或者有的公司为了省事儿,通常会让一人独揽大权,所有的操作均是一个人在操作。同一个人开发,同一个人上线,同一个人审批,这就是权限不分,这样就很危险了,只要一个人,就能完成任何的操作。所以,不同的人员要进行不同的权限管理,在进行上线和维护修改时,上线和审批权限进行分开管理。区分业务运维、系统运维、网络运维、DBA等多重角色,每个角色都只能接触自己所负责的那票业务服务器,以及相应可执行的权限。 3.3 备份 # 备份、备份、备份。一定要做好备份,无论是代码还是数据,都要及时地备份,是每天备份还是每小时备份,就看业务的体量了,如果数据更新快,备份的频率就快一些。同时,备份的手段也要多一些: 异地备份,同时这两地需要不同的人员权限进行管理; 本地备份,在发布到线上后,本地要预留一份; 多云备份,例如你的业务部署在A云上,可以同步到B云上备份; 多重备份,都要设置不同的权限,当线上数据被破坏后,都可以从其他备份的数据进行恢复。 4. 总结 # 其实写博客也是一样的,无论是在博客平台,还是自有博客,若你的账号被封,或者他的博客平台出现问题,都可能会造成你博客文章的丢失。不论他们平台做了什么措施,至少自己这里也是要备份的。
2024年10月20日
6 阅读
0 评论
0 点赞
2024-10-20
代码管理:请立即删除你不用的代码
我们码农工程师在项目长期的维护过程中,经常会遇到一些目前暂时用不到的代码,然后我们习惯会注释掉这些代码,或者干脆另起一个文件重新编写。在什么情况下会留存代码呢? 业务需求发生变动,想着以后可能还会用上; 之前临时支撑的业务已结束,产品说后面还会有类似的活动; 通常我们留下的死代码规模有大有小,小的可能就是某个if-else分支,大的可能到支撑了一套完整的业务。现有的代码不整理,只会让代码越来越多,项目的规模越来越大。到最后,自己也不知道这些代码是否还用的到。注意:现在用不到的死代码,请果断地立即删除,而不是注释掉。为什么是直接删除呢? 你现在用不到的代码,以后也用不到了; 版本管理,即使以后用到了,也可以通过版本管理找回之前的代码; 之前若是支撑临时业务的代码,也请果断地删除。产品通常会说下次圣诞和元旦时,还会用到的。但,相信我,后面的需求肯定用不上现在的代码了。其实这就类似“破窗户理论”,一扇破窗户,只要有那么一段时间不修理,就回渐渐给建筑的居民带来一种废弃感——一种任何人都不关心这座建筑的感觉。于是又一扇窗户破了。人们开始乱扔垃圾。出现了乱涂乱画,严重的结构损坏开始了。在一段时间后,废弃感就变成了现实。当我们留下的死代码越来越多,我们也就越不在乎这些代码,最后导致整体都无法维护了。
2024年10月20日
6 阅读
0 评论
0 点赞
2024-10-20
腾讯抢金达人中倒计时的实现与改进
我们通过之前的《前端中的事件循环 eventloop 机制》中也能知道,setTimeout和setInterval的计时器并不是准确的,因为有其他任务的执行,会推迟定时器的执行。这对一些相对比较严格计时器来说,倒计时的时间越长,误差就会越大。倒计时通常有 2 种,一种是固定差值的倒计时,例如我们抢金达人中每题的答题时间是 10s;还有一种是固定时间点的倒计时,比如凌晨 0 点开始抢购。但这两种实现的方式都差不多。我们以抢金达人中的固定差值倒计时为例,来用几种方法实现这个倒计时。这种固定差值的倒计时,无所谓从什么时间点开始,我只需要有 10 秒钟的时间即可。 1. 计数器 # 最开始,我们在倒计时的过程中,为了增加用户的紧张心理,加了一个小数位,最简单的倒计时就实现了,每 100ms 减去 0.1,当进度减为 0 时,则结束:this.timer = setInterval(() => { const progress = this.state.progress; const _progress = (progress * 10 - 1) / 10; this.setState({ progress: _progress }); if (_progress 0) { setTimeout(() => { countdown(); }, delay - diff); // 每次进行校准 } } setTimeout(() => { countdown(); }, delay); 2. requestAnimationFrame # 与 setTimeout 相比,requestAnimationFrame 最大的优势是由系统来决定回调函数的执行时机。具体一点讲,如果屏幕刷新率是 60Hz,那么回调函数就每 16.7ms 被执行一次,如果刷新率是 75Hz,那么这个时间间隔就变成了 1000/75=13.3ms,换句话说就是,requestAnimationFrame 的步伐跟着系统的刷新步伐走。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题 3. 固定时间点的倒计时 # 以上两种方案都存在着一个问题,若当前标签页不可见时,或者在移动端被置于后台时,计时器均会被挂起或者变慢,导致重新回来后的计时器出错。比如当用户正在答题倒计时的过程中,当用户把 app 收到后台,倒计时就会停止,重新回到 app 后,倒计时接着之前的继续执行,这样是不对的。这里我就对之前使用的倒计时进行了改进,不再用计数器来计算当前剩余的时间,而是利用固定时间点的倒计时方式进行计算。每当要开始倒计时器之前,都先计算出结束时的时间戳是多少。然后每次渲染时就获取下当前时间戳与结束时间戳之间的差值。这样就即使是切换 tab,或者将 app 收到后台,都是没有影响的。但如果用户要修改它的本地时间,那就没办法了。我们也只是从精准度上进行考虑,同时后端也加上对时间的校验,即使修改了前端时间,后端也是校验不通过的。const CountDown = () => { const endTime = useMemo(() => Date.now() + 1000 * 10, []); // 持续10s的时间 const [leftTime, setLeftTime] = useState(0); useEffect(() => { const count = () => { let now = Date.now(); const diff = endTime - now; if (diff >= 0) { setLeftTime((diff / 1000).toFixed(2)); requestAnimationFrame(count); } else { setLeftTime(0); } }; count(); }, [endTime]); return {leftTime}; }; 可以点击链接查看简单的 demo。当然,这只是很简单的功能,我们可以再添加几个配置,再完善下这个倒计时组件: 倒计时持续的时间或者结束时间点; 展示的倒计时格式; 频率,是每 100ms,还是每 1000ms 执行一次; 倒计时改变时的回调函数; 倒计时结束时的回调函数; 这里我们定义组件接收的参数类型为:interface CountDownProps { total?: number; // 倒计时的时间,单位毫秒 endTime?: number; // 结束的时间点,与 total 二选一,且优先级更高,单位毫秒 format: string | ((progress: number) => string); // 要展示的时间格式,可以是字符串或者函数 diff?: number; // 频率,单位毫秒ms onStart?: () => void; // 开始时的回调 onStep?: (step: number) => void; // 每次更新时执行的回调 onEnd?: () => void; // 结束时的回调 } 一个完整的组件在在于组件的健壮性和扩展性,我们这里也对外提供几个参数,方便调用。 format 接收两种类型:如果是字符串,则直接按照字符串要求的进行格式化;若是函数,调用方可以自己处理时间戳,并返回即可; 提供了 3 个关键时间点的回调函数,让调用方可以进行一些额外的处理,例如想在倒计时结束时进行弹窗等; 我们的频率字段 diff,在设定的值小于 17ms 时,直接使用 requestAnimationFrame 来代替进行页面刷新; 完整的代码可以访问 GitHub 仓库:react-countdown。调用方式: 'wenzi ' + progress} diff={10} onStep={(step) => console.log(step)} onEnd={() => console.log('end')} /> 还有更多的 demo 可以链接查看:react-countdown 的样例。 4. 总结 # 倒计时在我们日常项目应用地非常广泛,这里也是总结了下倒计时的用法,并形成一个通用的组件,当然,其中还有很多的不足,依然还需要进一步的完善。
2024年10月20日
4 阅读
0 评论
0 点赞
1
...
65
66
67
...
241