외부 리소스 로딩 감지:onload와 onerror 이벤트

onload와 onerror의 역할

  • onload: 리소스가 성공적으로 로드되고(그리고 실행까지 완료된 후) 발생합니다.
  • onerror: 리소스 로딩 중 문제(네트워크 실패, 잘못된 URL 등)가 발생했을 때 트리거됩니다.

동적 스크립트 로딩과 상태 감지

외부 스크립트를 동적으로 추가하고, 로딩이 완료된 후 해당 스크립트 내에 정의된 함수를 호출해야 하는 경우가 있습니다.

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>스크립트 로딩 감지</title>
  <style>
    #loadStatus { color: #555; margin-bottom: 10px; }
    #actionBtn { padding: 8px 16px; background: #4caf50; color: white; border: none; }
    #actionBtn:disabled { background: #ccc; cursor: not-allowed; }
  </style>
</head>
<body>
  <div id="loadStatus">라이브러리 로딩 중...</div>
  <button id="actionBtn" disabled>기능 실행</button>
  <script>
    const status = document.getElementById('loadStatus');
    const actionBtn = document.getElementById('actionBtn');

    const script = document.createElement('script');
    script.src = 'https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js';

    script.onload = () => {
      status.textContent = 'Axios 라이브러리 로드 완료!';
      actionBtn.disabled = false;
      actionBtn.addEventListener('click', () => {
        axios.get('https://api.example.com/data')
          .then(response => alert('데이터 로드 성공!'))
          .catch(err => alert('데이터 요청 실패'));
      });
    };

    script.onerror = () => {
      status.textContent = '스크립트 로드 실패';
      actionBtn.textContent = '오류 발생';
      actionBtn.disabled = true;
    };

    document.head.appendChild(script);
  </script>
</body>
</html>
  • onload: Axios 로드 후 버튼 활성화 및 API 요청 가능
  • onerror: 로드 실패 시 사용자 알림 및 버튼 비활성화

이미지 로딩 상태 관리

이미지 리소스도 onload와 onerror 이벤트를 지원하여 로딩 상태 추적을 할 수 있습니다. 새 Image 객체를 생성해 이미지 로딩 상태를 감지한 후, 로드된 이미지를 페이지에 삽입하거나 에러를 알리는 방식입니다.

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>이미지 로딩 추적</title>
  <style>
    #gallery { border: 1px solid #ddd; padding: 10px; min-height: 100px; }
    #imgStatus { font-size: 14px; color: #777; }
  </style>
</head>
<body>
  <div id="gallery"></div>
  <div id="imgStatus">이미지 로딩 중...</div>
  <script>
    const gallery = document.getElementById('gallery');
    const imgStatus = document.getElementById('imgStatus');

    const img = new Image();
    img.src = 'https://picsum.photos/300';

    img.onload = () => {
      gallery.appendChild(img);
      imgStatus.textContent = '이미지 로드 완료!';
    };

    img.onerror = () => {
      imgStatus.textContent = '이미지 로드 실패';
      const fallback = new Image();
      fallback.src = 'fallback.jpg'; // 대체 이미지
      gallery.appendChild(fallback);
    };
  </script>
</body>
</html>
  • onload: 이미지가 성공적으로 로드 완료
  • onerror: 실패 시 상태 표시 및 대체 이미지 삽입

CORS와 오류 처리

브라우저 보안 정책 때문에, 다른 도메인에서 로드한 스크립트나 리소스에서 에러가 발생하면 구체적인 에러 정보를 얻기 어려울 수 있습니다. 예를 들어, 동일 출처가 아닌 리소스에서 발생한 스크립트 에러는 "Script error."라는 간단한 메시지로만 전달됩니다. 이를 해결하기 위해서는 서버에서 Access-Control-Allow-Origin 헤더를 제공한다면, 스크립트 태그에 crossorigin 속성을 추가하여 더 자세한 오류 정보를 얻을 수 있습니다.

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>CORS 리소스 오류 처리</title>
</head>
<body>
  <h1>CORS 스크립트 로드</h1>
  <div id="errorLog"></div>
  <script>
    const errorLog = document.getElementById('errorLog');

    window.onerror = (msg, url, line, col, error) => {
      errorLog.textContent = `에러: ${msg}, URL: ${url}, 위치: ${line}:${col}`;
    };

    const script = document.createElement('script');
    script.crossorigin = 'anonymous';
    script.src = 'https://api.example.com/nonexistent.js';

    script.onload = () => {
      errorLog.textContent = '스크립트 로드 성공';
    };

    script.onerror = () => {
      errorLog.textContent = '스크립트 로드 실패 (세부 정보는 window.onerror 확인)';
    };

    document.head.appendChild(script);
  </script>
</body>
</html>

예제: Promise 기반 다중 리소스 로딩

function loadResource(type, src) {
  return new Promise((resolve, reject) => {
    const element = document.createElement(type);
    element.src = src;
    element.onload = () => resolve(element);
    element.onerror = () => reject(new Error(`로드 실패: ${src}`));
    document.head.appendChild(element);
  });
}

Promise.all([
  loadResource('script', 'https://cdn.example.com/lib1.js'),
  loadResource('script', 'https://cdn.example.com/lib2.js')
])
  .then(() => console.log('모든 스크립트 로드 완료'))
  .catch(err => console.error(err));