프로그래밍/웹 관련

자바스크립트 코드 최적화 문제 #1

채윤아빠 2022. 2. 24. 08:51
728x90
반응형

프로젝트 실무에서 적용한 코드 리팩토링 예를 정리해 봅니다.

위 화면과 같이, 어떤 결과에 대해 화면에 테이블 형태로 표시하여주는 함수를 최적화하여 보았습니다.

/**
 * @brief 수행한 BIT 결과를 하단 상태바의 자체점검 결과에 표시합니다.
 * @param bit_results 수행한 BIT 결과를 담고 있는 객체
 */ 
function load_bit_results_on_footer(bit_results) {
    let elmTable = document.querySelector('#bit_latest_footer');
    if (elmTable == null) {
        elmTable = document.createElement('tr')
        elmTable.id = 'elmfooter'
        document.body.appendChild(elmTable)
    }
    if (bit_results == null || bit_results === null) {
        elmTable.innerHTML = `
            <div style="width:100%; height: 30px; text-align:center">
                    <p style="padding: 5px 0;">자체점검 수행 결과가 없습니다.</p>
            </div>`
    } else {
        elmTable.innerHTML = ''
        let strTR = '';
        let strTBody = '';

        let req_equips = bit_results.req_equips;
        let result_summary = bit_results.result_summary;
        let results_msg = JSON.parse(bit_results['results_msg']);
        let end_time = bit_results.end_time;
        let equip_index = 0;

        let white = `자체점검을 수행하고 있습니다.`;
        let black = `자체검검을 요청하지 않았습니다.`;

        strTR += `<tr>`
        strTR += `<td style="width: 10%;" rowspan="2">자체점검 현황</td>`;
        if(result_summary == null) {
            for ( ; equip_index < 7 ; equip_index ++) {
                strTR += `<td><button type="button" class="button circle white" style="cursor: default" title="${white}"></td>`;
            }
        } else {
            for ( ; equip_index < 7 ; equip_index ++) {
                if(equip_index == 0) {
                    results_msg_edit = String(results_msg.SOK);
                } else if(equip_index == 1) {
                    results_msg_edit = String(results_msg.HSC);
                } else if(equip_index == 2) {
                    results_msg_edit = String(results_msg.SGC);
                } else if(equip_index == 3) {
                    results_msg_edit = String(results_msg.FMS);
                } else if(equip_index == 4) {
                    results_msg_edit = String(results_msg.DPS);
                } else if(equip_index == 5) {
                    results_msg_edit = String(results_msg.UPS);
                } else if(equip_index == 6) {
                    results_msg_edit = String(results_msg.PRT);
                }

                if ( (req_equips & (0x01 << equip_index)) > 0 ) {
                    if ( (result_summary & (0x01 << equip_index)) > 0) {
                        if(equip_index == 1) {
                            strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle green" style="cursor: pointer" title="${results_msg_edit}" onclick="open_common_bit_results(${bit_results.sok_result});"></td>`;
                        } else {
                            strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle green" style="cursor: default" title="${results_msg_edit}"></td>`;
                        }
                    } else {
                        if (equip_index != 6) {
                            if(equip_index == 1) {
                                strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle red" style="cursor: pointer" title="${results_msg_edit}" onclick="open_common_bit_results(${bit_results.sok_result});"></td>`;
                            } else {
                                strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle red" style="cursor: default" title="${results_msg_edit}"></td>`;
                            }
                        } else {
                            strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle yellow" style="cursor: default" title="${results_msg_edit}"></td>`;
                        }
                    }
                } else {
                    strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle black" style="cursor: default" title="${black}"></td>`;
                }
            }

            if (end_time != null) {
                strTR += `<td style="width: 20%; border-right: none; color: #7d7d7d; cursor: default" rowspan="2">${bit_results['end_time']}</td>`;
            } else {
                strTR += `<td style="width: 20%; border-right: none; color: #7d7d7d; cursor: default" rowspan="2"> - </td>`;
            }
            strTR += `</tr>`;

            strTR += `<tr class="footer_title">`
            strTR += `<td style="padding: 5px 0;">탐색기 제어기 PC</td>`;
            strTR += `<td style="padding: 5px 0;">탐색기</td>`;
            strTR += `<td style="padding: 5px 0;">신호발생기</td>`;
            strTR += `<td style="padding: 5px 0;">비행운동시뮬레이터</td>`;
            strTR += `<td style="padding: 5px 0;">전원공급기</td>`;
            strTR += `<td style="padding: 5px 0;">무정전전원장치</td>`;
            strTR += `<td style="padding: 5px 0;">잉크젯 프린터</td>`;
            strTR += `</tr>`;
        }
        strTBody += strTR;
        elmTable.innerHTML = strTBody;
    }
}

코드 리팩토링을 위하여 가장 먼저 눈에 보인 부분은 다음과 같은 부분입니다.

            for ( ; equip_index < 7 ; equip_index ++) {
                if(equip_index == 0) {
                    results_msg_edit = String(results_msg.SOK);
                } else if(equip_index == 1) {
                    results_msg_edit = String(results_msg.HSC);
                } else if(equip_index == 2) {
                    results_msg_edit = String(results_msg.SGC);
                } else if(equip_index == 3) {
                    results_msg_edit = String(results_msg.FMS);
                } else if(equip_index == 4) {
                    results_msg_edit = String(results_msg.DPS);
                } else if(equip_index == 5) {
                    results_msg_edit = String(results_msg.UPS);
                } else if(equip_index == 6) {
                    results_msg_edit = String(results_msg.PRT);
                }

Javascript에서 "results_msg.SOK"과 같이 JSON 객체의 속성을 접근할 수도 있지만, results_msg['SOK']와 같은 식으로도 접근이 가능합니다.

그래서 이 부분은 다음과 같은 형식으로 코드를 정리할 수 있습니다.

            let arrEquips = [ 'SOK', 'HSC', 'SGC', 'FMS', 'DPS', 'UPS', 'PRT' ];
            for( ; equip_index < 7 ; equip_index ++) {
                let circle_title = String(results_msg[arrEquips[equip_index]]);

그리고, BIT 결과에 따라 원의 색 정보 및 오류 내용으로 설정하는 부분이 있는데, 이를 위하여 모든 부분에서 아래와 같이 경우에 따라 문자열을 계속 수행하고 있었습니다.

                        if(equip_index == 1) {
                            strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle green" style="cursor: pointer" title="${results_msg_edit}" onclick="open_common_bit_results(${bit_results.sok_result});"></td>`;
                        } else {
                            strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle green" style="cursor: default" title="${results_msg_edit}"></td>`;
                        }

                        // ....

이 부분을 "<TD> ... </TD>" 열에서 결과에 따라 변경되는 것들만 따로 변수화하여, 최종적으로 마지막에서만 문자열 연산을 하도록 수정하였습니다.

                // ... ; 결과에 따라 circle_color, circle_title, onclick_condition만 할당하도록 함

                strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle ${circle_color}" style="cursor: default" title="${circle_title}" ${onclick_condition}></td>`;

 

최종 코드를 리팩토링한 결과는 다음과 같습니다.

참고하시기 바랍니다.

/**
 * @brief 수행한 BIT 결과를 하단 상태바의 자체점검 결과에 표시합니다.
 * @param bit_results 수행한 BIT 결과를 담고 있는 객체
 */ 
function load_bit_results_on_footer(bit_results) {
    let elmTable = document.querySelector('#bit_latest_footer');
    if(bit_results == null || bit_results === null) {
        elmTable.innerHTML = `
            <div style="width:100%; height: 30px; text-align:center">
                <p style="padding: 5px 0;">자체점검 수행 결과가 없습니다.</p>
            </div>`
    } else {
        elmTable.innerHTML = ''
        let strTR = '';
        let strTBody = '';

        let req_equips = bit_results.req_equips;
        let result_summary = bit_results.result_summary;
        let results_msg = JSON.parse(bit_results['results_msg']);
        let end_time = bit_results.end_time;
        let equip_index = 0;

        strTR += `<tr>`
        strTR += `<td style="width: 10%;" rowspan="2">자체점검 현황</td>`;

        if(result_summary == null) { // 자체점검을 수행하고 있는 경우
            let white_title = `자체점검을 수행하고 있습니다.`;
            for( ; equip_index < 7 ; equip_index ++) {
                strTR += `<td><button type="button" class="button circle white" style="cursor: default" title="${white_title}"></td>`;
            }
        } else {
            let arrEquips = [ 'SOK', 'HSC', 'SGC', 'FMS', 'DPS', 'UPS', 'PRT' ];
            for( ; equip_index < 7 ; equip_index ++) {
                let circle_color = 'green';
                let circle_title = String(results_msg[arrEquips[equip_index]]);
                let onclick_condition = '';

                if(equip_index == 1) { // 탐색기인 경우 onClick 기능 추가
                    onclick_condition = `onClick="open_common_bit_results(${bit_results.sok_result});"`
                }

                if((req_equips & (0x01 << equip_index)) > 0) {
                    if((result_summary & (0x01 << equip_index)) > 0) {
                        // 성공
                        circle_color = 'green'
                    } else { // 실패
                        circle_color = 'red'
                        if(equip_index == 6) { // 잉크젯 프린터인 경우 yellow
                            circle_color ='yellow'
                        }
                    }
                } else { // 자체점검을 요청하지 않은 경우
                    circle_color = 'black'
                    circle_title = `자체검검을 요청하지 않았습니다.`
                }
                strTR += `<td class="center" style="width: 10%;"><button type="button" class="button circle ${circle_color}" style="cursor: default" title="${circle_title}" ${onclick_condition}></td>`;
            }
        }

        end_time_string = '-'
        if(end_time != null) {
            end_time_string = bit_results['end_time']
        }
        strTR += `<td style="width: 20%; border-right: none; color: #7d7d7d; cursor: default" rowspan="2">${end_time_string}</td>`;
        strTR += `</tr>`;

        let title_arrEquips = [ '탐색기 제어기 PC', '탐색기', '신호발생기', '비행운동시뮬레이터', '전원공급기', '무정전전원장치', '잉크젯 프린터' ];
        strTR += `<tr style="width: 10%; font-size: 9px;">`;
        title_arrEquips.forEach(function(title_arrEquip) {
            strTR += `<td style="padding: 5px 0;">${title_arrEquip}</td>`;
        });
        strTR += `</tr>`;

        strTBody += strTR;
        elmTable.innerHTML = strTBody;
    }
}