Помните о низкоуровневой и серьезной ошибке разработки

JavaScript спецификация кода

1. Введение

Я работал над интерфейсом более двух лет, исправил бесчисленное количество ошибок, написал бесчисленное количество ошибок, вырыл много ям, заполнил много ям, сделал много ошибок, исправлял много раз и много раз учился. Вообще говоря, по багам и ямам они все чинятся или заполняются, и помните, почему возникали баги, почему есть ямы, почему допустили ошибки, как их решить и как их избежать в следующий раз. На этот раз я думал, что разработка идет хорошо, но после разработки я понял, что допустил незначительную и серьезную ошибку, я размышлял о такой ошибке.

2. Причина

В день 9 марта компания провела мероприятие, надеясь использовать викторину для продвижения собственного апплета. В результате из-за слишком сжатых сроков разработки апплет был отправлен на рассмотрение только 5 марта. Утром 8 марта апплет еще не был рассмотрен.В крайнем случае ответная деятельность может быть выполнена только в виде веб-страницы и разработана с использованием Vue. Поскольку эта викторина будет использоваться 9 марта, разработка, тестирование и приемка должны быть завершены 8 марта.

Процесс разработки прошел очень гладко, просто изменили часть кода апплета на то, как Vue разрабатывает мобильные сайты, изменили метки, немного переписали стиль, и проект заработал.Используя API апплета, вы можете только найти хороший способ заменить его, но проблема в основном не большая.

Одно из неприятных требований: когда пользователь завершает работу на полпути, не ответив на вопрос, статус ответа пользователя должен быть записан. Например, на какие вопросы были даны ответы, какие были неправильными, какие были правильными и сколько баллов было получено. В апплете легко использовать функцию жизненного циклаunload()контролировать. Когда пользователь покидает страницу, не ответив на вопрос, текущие данные ответа пользователя передаются в фон, и фон сохраняется. Когда пользователь входит на страницу в следующий раз, я могу отобразить информацию в соответствии со статусом ответа пользователя, возвращенным из фона. Если пользователь не ответил на вопрос, он начнет отвечать на вопрос снова.Если пользователь не ответил на вопрос в прошлый раз, пользователю будет предложено ответить на вопрос снова в соответствии с ходом выхода.Если ответ будет завершена, страница результатов ответа будет отображаться непосредственно.

Это требование несложно выполнить, апплет имеетonload() иunload() Две функции жизненного цикла, просто дважды вызовите интерфейс в этих двух функциях.

Но на веб-странице легко отслеживать пользователя, заходящего на страницу. Но мониторинг страницы выхода пользователя (кнопка «возврат» или «закрыть» в браузере WeChat) не работает. Это самое распространенное решение в Интернете, но я не знаю, проблема ли это в том, как я его использую, или в моем персонаже.

Ответ приходит от Чжиху:Собственная среда браузера WeChat для отслеживания событий кнопки возврата и закрытия в верхнем левом углу?

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 вопросов с несколькими вариантами ответа требуется около двух минут, что эквивалентно 9-кратному увеличению количества ответов с сервера в течение 2 минут.Это бремя внезапно становится намного тяжелее. Просто эти запросы в основном бессмысленны, потому что большинство людей, 10 вопросов, около двух минут времени ответа, не бросят на полпути, что эквивалентно тому, что я делаю что-то бессмысленное и потребляющее производительность сервера.

Причина, которая заставляет меня задуматься, заключается в том, что я всегда строго контролировал количество запросов, хотя сейчас компания мало думает о производительности и нагрузке на сервер. Но это вызывает мое обсессивно-компульсивное расстройство.

4. Схема декомпрессии

Из-за активности по вопросам и ответам я должен использовать его 9-го числа, и я вспомнил об этом только тогда, когда болтал с коллегами после душа 8-го числа, поэтому у меня не было времени изменить его, потому что это также требует времени для разработки и тестирования. 9-го числа, поскольку мой коллега попросился в отпуск, я также отвечал за его проект, который также был относительно поспешным, и у меня не было много времени, чтобы изменить его. Могу только обидеться на сервер.

Тем не менее, но есть и другие решения по снижению нагрузки на сервер, о них мне еще нужно рассказать, это можно расценивать как напоминание себе, а можно расценивать как напоминание всем. Одна вещь, на которую следует обратить внимание в развитии: не торопитесь, не торопитесь, не торопитесь.

PS: На тот момент было почти 4:30 дня, а еще оставались две разрозненные функции, которые не были сделаны, и их нужно было тестировать заново. Долго искал решение (мониторил "возврат" или "кнопка закрытия" WeChat) и нигде, спешил и голова была пустая, вот и подумал об этом методе.

куки или локальный магазин

Запись статуса пользователя должна быть лучшим и самым простым решением.

Например, использование файлов 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)
        }
    })
}

В приведенном выше коде может быть сложнее использовать куки, но там всего несколько строк, не так много, но это уменьшает много запросов.

Это решение не используется в апплете, просто учитывая, что пользователь выходит из апплета, кэш может очищаться, хотя вероятность этого невелика, поэтому функция жизненного цикла используется дляunload()Для мониторинга пользователь будет отправлять прогресс ответа пользователя в фон после выхода, и пусть фон записывает.Не будет много случаев, или даже ни одного, и не будет много запросов, поэтому это решение было использовано на то время. Никакие файлы cookie или localstore не используются.

Несколько замечаний:

1.Независимо от ситуации,разработка требует ясного ума,потому что когда ум не ясен,все что пишут-баги.Это разовая деятельность.Если это долгосрочный проект,я обязательно сделаю рефакторинг это, потому что это было написано в то время код отстой. Также легко сделать некоторые ошибки низкого уровня.

2. Не думайте слишком много о событиях с малой вероятностью, которые доставят неприятности вам, коллегам и серверам, а также повлияют на ход проекта. В этот раз я слишком много думал, и оказалось, что время для испытаний запоздало, время для приемки запоздало, и я сам наделал ошибок. Последствия слишком долгих размышлений могут заключаться в том, что вы собираете семена кунжута, теряете арбуз или даже крадете цыплят, не теряя при этом риса.

2. Резюме

Эта ошибка подошла к концу, и я также подытожил, почему меня больше смущает эта ошибка.

1. Недавно я искал, как оптимизировать код, чтобы сделать его более читабельным и удобным в сопровождении. Но сделал ошибку слишком много запросов. Позаботьтесь об этом.

2. Второе, что из-за этой ошибки последствия были слишком серьезными, и 90% запросов были непосредственно увеличены. Последствия прошлых ошибок были не так серьезными.

3. Когда я делал ошибки в прошлом, я мог найти это до того, как проект был онлайн, и иногда менялся, на этот раз, на этот раз обнаруживается, но нет времени изменить.

4. Те, кто думает, что не будет ошибок, которых не следует делать. Может быть, ты совершишь эти ошибки, когда твой разум не ясен Ты всегда должен быть осторожен На этот раз я напоминаю себе.

Однако концовка все равно была хорошей, из-за нехватки времени вопросно-ответная деятельность в этот день не проводилась, поэтому сервер не тестировался. Если сервер не выдержит нагрузки и рухнет в тот день, возможно, мне придется взять на себя вину и уйти в отставку!

Ну история такая, немного похоже на дневник, надеюсь всем понятно. Если в статье есть какая-либо ошибка, пожалуйста, дайте указатели и обменяйтесь.


-------------------- Великолепная разделительная линия --------------------

Хотите узнать больше, обратите внимание на мой публичный аккаунт WeChat: В ожидании книжного магазина