1.前言
前端从事了超过两年,修复了无数的bug,写了无数的bug;挖了很多次坑,填了很多次坑;犯了很多次错,弥补了很多次,学习了很多次。一般而言,对于bug、坑,都是修复完了或者填完了,并且记住为什么会产生bug,为什么有坑,为什么犯错,怎么解决的,下次怎么避免,就行了,就学习到了。而这一次的项目,原本以为开发挺顺利的,但是开发完了,才发现自己犯了一个低级而严重的错,这样的一个失误,我一直耿耿于怀。
2.起因
在3月9号的这一天,公司有个活动,希望用答题活动推广自己的小程序。结果因为开发时间太紧,小程序在3月5号才提审。在3月8号早上,小程序还没有审核,在不得已的情况下,只能把答题活动以网页的形式进行,使用vue开发。由于在3月9号要用到这个答题活动,所以3月8号必须要完成开发,测试,验收。
开发的过程,都挺顺利,只是把小程序的一些代码,改成vue开发移动端网站的方式,把标签换了,样式稍微重写一下,项目就跑起来了,至于一些交互逻辑,由于不能使用小程序的API,只能另找良方代替,但问题基本不大。
麻烦的一个需求就是:当用户没答完题中途退出的时候,要记录用户的答题状态。比如答了哪些题目,哪些题目错了,哪些题目正确了,拿了多少分等数据。在小程序里面,很轻松可以利用生命周期函数
unload()
进行监听。当用户没答完题退出页面的时候,把用户当前的答题数据,传给后台,让后台进行保存。在用户下次进入页面的时候,我可以根据后台返回的用户答题状态,进行信息的展示。如果用户没答过题目,就重新开始答题,如果用户上次退出的时候,没答完题目,就按照退出时的进度,让用户重新答题,如果答完了题目,直接显示答题结果页面。
这个需求不难实现,小程序有
onload()
和
unload()
两个生命周期函数,只是在这两个函数里面,调两次接口而已。
但在网页里面,监听用户进入页面简单。但是监听用户退出页面(微信浏览器上面的那个‘返回’或者‘关闭’按钮)却死活不行。网上最多的解决方案是这个,但是不知道是我使用方式有问题还是人品问题,压根没用,无论是微信开发者工具,还是安卓或者苹果真机。
答案来自知乎: 微信自带浏览器环境内左上角返回、关闭按钮事件监控?
pushHistory();
window.addEventListener("popstate", function(e) {
alert("我监听到了浏览器的返回按钮事件啦");//根据自己的需求实现自己的功能
}, false);
function pushHistory() {
var state = {
title: "title",
url: "#"
};
window.history.pushState(state, "title", "#");
}
根据网上的方案,试了几个(包括vue的生命周期函数),没一个可行的。最后无奈之下,只能用一个蠢方法,用户点击每一题选项的时候,就把用户当前的记录,通过接口发给后台,让后台记录。这个就是我该文章说的低级严重的失误,想必大家也知道是怎么回事了。
3.失误分析
这次的答题活动,一共有三轮,每轮10道题,现场大概有500人答题。本来使用小程序开发,不管用户是没答题就让用户可以开始答题,答题途中退出就记录状态,答完题就显示结果。在这个过程中,我跟后台交互的只有两次:一次是用户进来的时候获取用户答题进度,一次是用户答完了最后一题,发送用户成绩,让后台记录;或者中途退出,发送用户答题进度给后台,让后台记录。
但是后来我在网页中,由于暂时没法监听用户是否退出,所以选择了用户回答完每一题的时候,把数据发给后台,让后台答题进度。这样请求数就多了N倍。服务器的压力就大了很多。
由于用户进来,无论是小程序还是网站,都要请求接口,获取用户答题数据,这次不在对比范围。这样原本小程序只需要和后台进行一次握手,但是在网页中,采用了不合适的方式,和后台握手次数变成了10次。足足多了9倍。如果是500人,每一轮从原本的500次,变成了5000次,三轮就从原本的1500次,变成了15000次!一般而言,10道题选择题,是两分钟左右的回答时间,就相当于在2分钟内服务器要响应的次数多了9倍,这个担子突然重了很多。而已这些请求,基本都有没什么意义的,因为绝大部分的人,10道题,大概两分钟的答题时间里面,不会中途退出,相当于我做了一件没意义,又消耗服务器性能的事情。
让我耿耿于怀的原因,我一向对请求数严格的控制,虽然现在公司不怎么考虑性能,服务器压力。但是这会引起我的强迫症。
4.解压方案
由于答题活动,9号要使用,而我是8号晚上洗完澡的时候和同事聊天的时候才想起,所以我没时间改了,因为改了也是需要时间开发,测试。9号由于同事请假,他的项目也由我负责,也是比较赶的项目,我也没那么多时间改。只能委屈一下服务器了。
说是这样说,但是关于其他的给服务器减轻负担的方案,还是有比较讲一下,算是给自己提个醒,也算是给大家提个醒。开发要注意一点:不要急,不要急,不要急。
PS:当时就是看着时间差不多是下午四点半了,然后还有两个零散功能没做,又要测试。找了很久的解决方案(监听微信的‘返回’或者‘关闭按钮’)都没下落的情况下,一下急了,脑袋放空,就想了那个方法。
cookie或者localstore
记录用户的状态,这个应该是最好的解决方案了,也应该是最简单的解决方案。
比如使用cookie记录用户的答题进度。在用户每答一题的时候,就把cookie记录到的数据,更新一次。这样只需要在用户答完了最后一题的时候再把用户的成绩发给后台就好,至于用户中途退出也没有,根据cookie判断就好,如果cookie有记录到用户的数据。就显示上次用户退出时候的题目,让用户继续答题。
原代码:
/**
* @dedependson 点击选项
* @index 题目索引 number
* @item 当前选项对象 object
*/
chooseDo(index,item){
/*其他代码略*/
let _this=this;
let _data={
qid:_this.qid,//答题轮次,如'2'代表第二轮答题