记一次初级并严峻的开辟失误

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'代表第二轮答题
        questions:_this.questions,//已答问题,'1,2,3'这个示意id为1,2,3的问题已回复了
        totalScore:_this.totalScore//当前得分
    }
    //发送要求,让背景纪录用户答题进度
    this.$http.post(http_url.submit,_data,{emulateJSON:true}).then(res=>{
            
    })
}

然后再到页面加载的时刻

mounted(){
    this.$http.get(http_url.getQuestions,{
        params:{
            qid:this.qid
        }
    }).then(res=>{
        res=res.body;
        //假如要求胜利
        if(res.code===0){
            //假如用户没答完题 0-没最先答题 1-没答完题   2-答完问题
            if(res.datas.status!==2){
                //猎取答题的问题
                this.questionList=res.datas.entryList;
                //假如问题小于10,就是最先答题了,然则没答完(半途退出的缘由)
                if(this.questionList.length<10){
                    //显现答题页面,让用户答题
                    this.questionListShow=true;
                }
                //不然就是没答过问题,让用户答题
                else{
                    //显现最先答题页面(答题首页,用户须要点击最先答题)
                }
            }
            //假如用户已答完题,显现效果页
            else{
                //代码略
            }
        }
        else{
            alert(res.msg)
        }
    })
}
       

cookie计划

chooseDo(index,item){
    /*其他代码略*/
    let _this=this;
    let _data={
        qid:_this.qid,//答题轮次,如'2'代表第二轮答题
        questions:_this.questions,//已答问题,'1,2,3'这个示意id为1,2,3的问题已回复了
        totalScore:_this.totalScore//当前得分
    }
    //保留cookie一天
    //_this.qid作为答题轮次的标识
    setCookie('answer-qid'+_this.qid,_this.qid,1);
    setCookie('answer-questions'+_this.qid,_this.questions,1);
    setCookie('answer-totalScore'+_this.qid,_this.totalScore,1);
}    

cookie函数参考:ec-do

//设置cookie
setCookie(name, value, iDay) {
    let oDate = new Date();
    oDate.setDate(oDate.getDate() + iDay);
    document.cookie = name + '=' + value + ';expires=' + oDate;
},
//猎取cookie
getCookie(name) {
    let arr = document.cookie.split('; '),arr2;
    for (let i = 0; i < arr.length; i++) {
        arr2 = arr[i].split('=');
        if (arr2[0] == name) {
            return arr2[1];
        }
    }
    return '';
},
//删除cookie
removeCookie(name) {
    this.setCookie(name, 1, -1);
}, 

然后再到页面加载的时刻,处理体式格局的转变。


mounted(){
    this.$http.get(http_url.getQuestions,{
        params:{
            qid:this.qid
        }
    }).then(res=>{
        res=res.body;
        //假如要求胜利
        if(res.code===0){
            //假如用户没答完题 0-没最先答题 1-没答完题   2-答完问题
            if(res.datas.status!==2){
                //纪录答题轮次
                this.qid=res.datas.qid; 
                //猎取答题的问题
                this.questionList=res.datas.entryList; 
                //假如用户半途退出,我们没有和背景对接口,背景没法纪录用户答题进度,所以此次要求,返回的效果要么是没最先答题,要么是答完题了。
                //要复原用户答题纪录,要运用cookie
                //假如存在cookie纪录,那末用户肯定是最少答过一题,复原用户答题进度
                let _answerQid=getCookie('answer-qid'+this.qid)
                _answerQuestions=getCookie('answer-qid'+this.qid).split(',');
                //字符串转整数
                _answerQuestions.map(item=>+item);
                
                if(_answerQid&&_answerQuestions){
                    this.questionList.fifler(item=>{
                        //item.id是问题的id
                        //假如问题的id存在,就过滤掉
                        _answerQuestions.indexOf(item.id)===-1
                    });
                    //显现答题页面,让用户答题
                    this.questionListShow=true;  
                }
                //不然就是没答过问题,让用户答题
                else{
                    //显现最先答题页面(答题首页,用户须要点击最先答题)
                }
            }
            //假如用户已答完题,显现效果页
            else{
                //代码略
            }
        }
        else{
            alert(res.msg)
        }
    })
}

代码上面,可以用了 cookie 会庞杂些,然则就多了几行罢了,差不了若干,反倒是减轻了许多要求。

在小顺序没有运用这个计划,就是斟酌到用户退出小顺序,可以会消灭缓存,虽然这个几率不大,所以运用性命周期函数举行
unload()举行监听,用户退出就把用户答题进度提交给背景,让背景纪录,如许的状况不会许多,以至没有,要求不会许多,所以当时就用了这个计划。没有运用cookie或许localstore。

注重几点:

1.不管什么状况,开辟都须要一个苏醒的思想,因为思想不苏醒,写的都是bug,谁人运动是一个一次性的项目,假如是历久的,我肯定会重构的,因为当时写的代码太烂了。也轻易犯一些初级的毛病。

2.不要为了小几率的事宜想得太多,给本身,同事,服务器都带来贫苦,也影响项目进度。此次就是想得太多,效果提测的时刻晚了,验收的时刻晚了,本身也犯了毛病。想太多的效果可以就是捡了芝麻,漏了西瓜,以至是偷鸡不成蚀把米。

小结

此次的的失误就告一段落了,我也总结了一下,本身为何会对此次失误更更于怀。

1.近来一直在看怎样优化代码,让代码更有可读性,可维护性。却犯了要求数过量的错。左支右绌啊。

2.第二个就是因为此次失误,致使的效果太严峻了,直接多了90%的要求。以往失误致使的效果没怎样严峻。

3.以往出错的时刻,在项目上线之前可以发明,而且有时刻改,此次不一样,此次是发明了,然则没时刻改了。

4.那些认为不会有,不应该犯的错。可以就在思想不苏醒的时刻,就会犯这些毛病,不管什么时刻都得留个神,此次也算是我本身提示本身了。

不过结局是还算是好的,当天因为时刻关联,答题运动没有举行,所以服务器没有遭到磨练。假如当天服务器承受不住压力,崩了,我也可以要引咎辞职了!

好了,故事就是如许了,有点日志的觉得,愿望人人谅解下。假如文章有什么地方写错了,也迎接指导交换。

——————–华美的分割线——————-

想相识更多,关注关注我的微信民众号:等待书阁

《记一次初级并严峻的开辟失误》

    原文作者:守候
    原文地址: https://segmentfault.com/a/1190000013662019
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞