[Javascript] 자바스크립트 전역변수에 값이 대입이 안되는 문제:: JAVASCRIPT 비동기 처리

2019. 10. 15. 02:39에러해결법


프로젝트를 하던 도중, 전역변수에 값이 대입이 안되는 현상이 발생했습니다.

 

위사진은 회원가입 페이지를 구성한 화면인데 모든입력창에 입력을 했을 시에 회원가입의 버튼이 활성화 되는 이벤트가 적용되있습니다.

아래는  모든 항목이 true일 때 버튼이 활성화 되는 코드입니다.

/* 5. 회원가입 submit 버튼 */

let submitBtn = $("#submit-btn");

function finalCheck() {

    if (uidResult && pwResult && nameResult && emailResult) {
        submitBtn.removeAttr("disabled");
    } else {
        submitBtn.attr("disabled", "disabled");
    }

    console.log("uidResult : "+uidResult + " pwResult : "+pwResult + " nameResult : "+nameResult + " emailResult : "+emailResult);

}

 

문제는 모든 항목들을 입력했음에도 불구하고 버튼이 활성화가 되지 않는 버그가 발생했습니다.

 

확인 결과 이벤트함수를 실행했음에도 불구하고 전역변수의 값이 변경되지 않는 것이 찍힙니다.

 


Java와는 다른 Javascript의 코드처리법

 

아래는 회원가입의 버튼 및 입력창에 입력시 진행되는 코드입니다.

$(function () {

    // uid 입력창 keyup
    uidObj.on('keyup', function () {
        uidResult = false;
        idMsg.text("");
        finalCheck();
    });
    // uid 중복검사 button click
    $(".uid-check").on('click', function () {
        joinIdCheck();
        finalCheck();
    });
    // pw 입력창 keyup
    pwObj.on('keyup', function () {
        pwCheck();
        finalCheck();
    });
    pwckObj.on('keyup', function () {
        pwCheck();
        finalCheck();
    });
});

 

또한 아래는 비교예시로 든 이벤트 함수의 코드입니다.

/* 1. ajax uid 중복 체크 */

let uidResult = false ;
let uidObj = $("#uid");
let idMsg = $("#id-msg");

function joinIdCheck() {
    uidResult = false;
    var uid = $("#uid").val();
    if(!regIdType(uid)){
        idMsg.removeClass('id-msg-green').addClass('id-msg-red');
        idMsg.text("소문자,숫자로 시작하는 특수문자[ - , _ ]조합으로 6~12자리내에 구성하세요.");
        return;
    }
    $.ajax({
        type    : "GET",
        url     : "/user/joinUidCheck?uid=" + uid,
        dataType: "text",
        success : function (result) {
            if (result == "UID_DUP") {
                idMsg.removeClass('id-msg-green').addClass('id-msg-red');
                idMsg.text("이미 사용중인 아이디입니다.");

            } else if (uid == "" || uid == null) {
                idMsg.removeClass('id-msg-green').addClass('id-msg-red');
                idMsg.text("아이디는 필수항목입니다.");

            } else if (result == "SUCCESS") {
                uidResult = true;
                idMsg.removeClass('id-msg-red').addClass('id-msg-green');
                idMsg.text("멋진 아이디네요!");
            }
        }, error: function (request, status, error) {
            console.log("code:" + request.status + "\n" + "message:" + request.responseText + "\n" + "error:" + error);
        }
    });
}

/* 3. 이름 입력 check */

let nameObj = $("#name");
let nameMsg = $("#name-msg");
let nameResult = false;

function nameCheck() {
    if (nameObj.val() == "" || nameObj.val() == null) {
        nameMsg.text("이름은 필수항목입니다.");
        nameResult = false;
    } else {
        nameMsg.text("");
        nameResult = true;
    }
}

 

아이디 중복체크 확인변수인 uidResult와 이름 입력체크 확인변수인 nameResult가 존재하고

각각의 이벤트 실행 시 이벤트 함수인 joinIdCheck()와 nameCheck()를 수행 후 버튼활성화 여부를 판단하기 위해 finalCheck() 함수를 실행시켜줍니다.

상단 : nameCheck() 실행       하단 : joinIdCheck()실행

이 때 , nameCheck()의 경우엔 전역변수의 값이 잘 전달되지만 joinIdCheck()의 경우 값이 전달되지 않는 것을 확인할 수 있습니다.

원인은 바로 Javasript의 비동기 처리법 때문이였다.

$(function () {
	
    let uidResult = false ;

    // uid 중복검사 button click
    $(".uid-check").on('click', function () {
        joinIdCheck();
        finalCheck();
    });
});

 

버그가 난 코드부분을 다시 보자면 위의 클릭이벤트는  ajax통신 코드를 진행하는 joinIdCheck()와 bool값을 판단하는 finalCheck가있습니다. 

만약에 joinIdCheck에서 통신을 실행시 응답이 계속 오지 않을 경우 어떻게될까요?

통신이 올때까지 끊임없이 기다려야 될것입니다... 이러한 코드들이 몇개 씩 실행되면 아마 웹 어플리케이션을 실행하는데 수십분은 걸릴지도 모르지요.

이러한 특정 로직의 실행이 끝날 때까지 기다려주지 않고 나머지 코드를 먼저 실행하는것을 비동기식처리라고 합니다.

자바스크립트에서는 비동기 처리를 사용해 ajax통신을 사용하는 joinIdCheck의 응답을 기다려주지 않고 먼저 finalCheck의 함수를 진행시켜버립니다.

당연히 초기에 false상태였던 uidResult의 경우 그대로 출력되기 때문에 false를 먼저 출력하게 되고 ,통신이 완료된 후 uidResult의 값을 true로 변경시켜주게 됩니다.


해결법

그렇다면 이를 어떻게 해결할까요?

방법은 바로 ajax의 통신 성공 후 finalCheck()를 실행시켜 주게 만들면 됩니다.

let uidResult = false ;

$(function () {
    // uid 중복검사 button click
    $(".uid-check").on('click', function () {
        joinIdCheck();
    });
 });
 
 
 /* 1. ajax uid 중복 체크 */

let uidObj = $("#uid");
let idMsg = $("#id-msg");

function joinIdCheck() {
    uidResult = false;
    var uid = $("#uid").val();
    if(!regIdType(uid)){
        idMsg.removeClass('id-msg-green').addClass('id-msg-red');
        idMsg.text("소문자,숫자로 시작하는 특수문자[ - , _ ]조합으로 6~12자리내에 구성하세요.");
        return;
    }
    $.ajax({
        type    : "GET",
        url     : "/user/joinUidCheck?uid=" + uid,
        dataType: "text",
        success : function (result) {
            if (result == "UID_DUP") {
                idMsg.removeClass('id-msg-green').addClass('id-msg-red');
                idMsg.text("이미 사용중인 아이디입니다.");

            } else if (uid == "" || uid == null) {
                idMsg.removeClass('id-msg-green').addClass('id-msg-red');
                idMsg.text("아이디는 필수항목입니다.");

            } else if (result == "SUCCESS") {
                uidResult = true;
                idMsg.removeClass('id-msg-red').addClass('id-msg-green');
                idMsg.text("멋진 아이디네요!");
            }
            finalCheck();
        }, error: function (request, status, error) {
            console.log("code:" + request.status + "\n" + "message:" + request.responseText + "\n" + "error:" + error);
        }

    });
}

 

위의 코드는 $(function) 때 실행했던 finalCheck()를 joinCheck()의 ajax success부분에 옮겨줍니다.

 

 

이후 콘솔창을 확인시 true값이 매우 잘 찍히는 것을 확인할 수 있습니다.

 

여담 : 이러한 패턴은 자바스크립트 코딩시 매우 자주 맞닥뜨리게됩니다. 때문에 callbackpromise에 대해 공부해 놓으면 이러한 문제를 쉽게 해결 할 수 있을것입니다.