Web/TroubleShooting

mouse over 시 ajax 통신으로 인한 과도한 통신 해소(캐싱처리)
깝몬 2025. 3. 4. 06:38

※ 보안을 위해 유사한 흐름의 코드를 작성하여 예시를 통해 설명합니다.

 

1. 문제의 발단

사원들의 목록페이지에서

 

사원의 이름에 마우스를 올릴경우 사원에 대한 상세한 정보를 모달창으로 보이는 기능이 존재한다.

 

이때 상세한정보의 모달은 ajax 통신을 통해 가져와서 xml형식의 데이터로 html 소스 원문을 가져와 만들도록 되어있었다.

 

이때 사원들의 이름을 마우스로 이리저리 움직이게 되면 수초안에 수십번의 통신을 요구하게된다.

 

이때 서버는 부하를 갖게되며 원활한 통신을 갖지못해 버벅임을 일으키게 된다.

 

예시코드

●사원 목록

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>사원 목록</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
        .employee-list { list-style: none; padding: 0; }
        .employee-list li { padding: 10px; cursor: pointer; border-bottom: 1px solid #ddd; }
        .modal { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
                 background: white; padding: 20px; border: 1px solid #ccc; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 
                 width: 300px; min-height: 150px; }
        .modal .close { cursor: pointer; float: right; font-size: 16px; }
    </style>
</head>
<body>

<h2>사원 목록</h2>
<ul class="employee-list">
    <li data-id="101">홍길동</li>
    <li data-id="102">김철수</li>
    <li data-id="103">이영희</li>
</ul>

<!-- 모달 창 -->
<div class="modal" id="employeeModal">
    <span class="close" onclick="closeModal();">&times;</span>
    <div id="modalContent">로딩 중...</div>
</div>

<script>
document.addEventListener("DOMContentLoaded", function () {
    document.querySelectorAll(".employee-list li").forEach(item => {
        item.addEventListener("mouseenter", function () {
            const employeeId = this.getAttribute("data-id");

            // 모달 표시
            document.getElementById("employeeModal").style.display = "block";
            document.getElementById("modalContent").innerHTML = "로딩 중...";

            // fetch로 다른 페이지에서 데이터를 가져오기
            fetch(`employeeDetail.html?id=${employeeId}`)
                .then(response => response.text())
                .then(data => {
                    document.getElementById("modalContent").innerHTML = data;
                })
                .catch(error => {
                    document.getElementById("modalContent").innerHTML = "<p>정보를 가져오는 데 실패했습니다.</p>";
                });
        });
    });
});

function closeModal() {
    document.getElementById("employeeModal").style.display = "none";
}
</script>

</body>
</html>

 

●모달창을 가져올 페이지

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>사원 정보</title>
</head>
<body>
<script>
    // URL에서 id 값을 가져오기
    const urlParams = new URLSearchParams(window.location.search);
    const employeeId = urlParams.get("id");

    // 사원 데이터 (예제)
    const employees = {
        "101": { name: "홍길동", department: "개발팀", email: "hong@example.com" },
        "102": { name: "김철수", department: "영업팀", email: "kim@example.com" },
        "103": { name: "이영희", department: "디자인팀", email: "lee@example.com" }
    };

    // 데이터 확인 후 출력
    if (employees[employeeId]) {
        document.write(`
            <p><strong>이름:</strong> ${employees[employeeId].name}</p>
            <p><strong>부서:</strong> ${employees[employeeId].department}</p>
            <p><strong>이메일:</strong> ${employees[employeeId].email}</p>
        `);
    } else {
        document.write("<p>사원 정보를 찾을 수 없습니다.</p>");
    }
</script>
</body>
</html>

 

 

 

2.해당 상황을 개선하기 위해 사용할개념 : 캐싱

캐싱을 활용하는 이유

  1. 반복적인 서버 요청 방지 → 같은 사원 정보를 요청할 경우 다시 서버 요청을 하지 않고 저장된 데이터를 사용.
  2. 페이지 로딩 속도 향상 → 요청 없이 캐싱된 데이터를 즉시 모달에 표시하여 빠른 반응 제공.
  3. 서버 부하 감소 → 불필요한 요청을 줄여 서버의 처리량을 최적화.

적용 방식

  • JavaScript 객체(cache)를 사용하여 데이터 저장.
  • 처음 요청 시 fetch로 데이터를 받아 캐시에 저장.
  • 이후 같은 데이터를 요청하면 fetch 없이 캐싱된 데이터 사용.

 

 

3. 개선된코드

 

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>사원 목록 (캐싱 적용)</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
        .employee-list { list-style: none; padding: 0; }
        .employee-list li { padding: 10px; cursor: pointer; border-bottom: 1px solid #ddd; }
        .modal { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
                 background: white; padding: 20px; border: 1px solid #ccc; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                 width: 300px; min-height: 150px; }
        .modal .close { cursor: pointer; float: right; font-size: 16px; }
    </style>
</head>
<body>

<h2>사원 목록</h2>
<ul class="employee-list">
    <li data-id="101">홍길동</li>
    <li data-id="102">김철수</li>
    <li data-id="103">이영희</li>
</ul>

<!-- 모달 창 -->
<div class="modal" id="employeeModal">
    <span class="close" onclick="closeModal();">&times;</span>
    <div id="modalContent">로딩 중...</div>
</div>

<script>
document.addEventListener("DOMContentLoaded", function () {
    let cache = {}; // 캐싱을 위한 객체

    document.querySelectorAll(".employee-list li").forEach(item => {
        item.addEventListener("mouseenter", function () {
            const employeeId = this.getAttribute("data-id");

            // 모달 표시
            document.getElementById("employeeModal").style.display = "block";
            document.getElementById("modalContent").innerHTML = "로딩 중...";

            // 캐시에 데이터가 있다면 즉시 사용
            if (cache[employeeId]) {
                document.getElementById("modalContent").innerHTML = cache[employeeId];
            } else {
                // 없으면 fetch 요청 후 저장
                fetch(`employeeDetail.html?id=${employeeId}`)
                    .then(response => response.text())
                    .then(data => {
                        cache[employeeId] = data; // 캐싱 저장
                        document.getElementById("modalContent").innerHTML = data;
                    })
                    .catch(error => {
                        document.getElementById("modalContent").innerHTML = "<p>정보를 가져오는 데 실패했습니다.</p>";
                    });
            }
        });
    });
});

function closeModal() {
    document.getElementById("employeeModal").style.display = "none";
}
</script>

</body>
</html>

 

 

 

요점으로는 mouse over시 미리 javascript에 처리해둔 데이터를 보여주는 방식으로 변경한것이다.

 

이로인해 서버의 부담을 덜고 사용자 입장에서도 로딩시 미세한 로딩시간의 증가로 사용성이 증가되게 된다.