{"componentChunkName":"component---src-templates-blog-post-js","path":"/frontendPerformance/lazyImagLoad/","result":{"data":{"site":{"siteMetadata":{"title":"Zayden","author":"[Your Name]","siteUrl":"https://gatsby-starter-bee.netlify.com","comment":{"disqusShortName":"","utterances":"JaeYeopHan/gatsby-starter-bee"},"sponsor":{"buyMeACoffeeId":"jbee"}}},"markdownRemark":{"id":"1b89781f-d5d4-5fff-89f3-54b8fbeaade3","excerpt":"저는 해당 도서에서 제공해주는 샘플코드를 이용하고 있으므로 샘플코드가 없으신분들은 최적화하는 과정에 대해서만 알고계서도 좋을것같습니다. 네트워크 분석 네트워크를 확인할 때는 명확한 흐름을 파악할 수 있도록 네트워크에 throttling을 적용합니다. 물론 기본으로 제공되는 ‘Fast 3G’ 나 ‘Slow 3G’ 설정을 적용 할 수 있으나 이번에는 기본 설정보다 조금 더 빠른 환경으로 설정하기 위하여 직접 커스텀 설정을 만들어 보겠습니다.  throttling 옵션엣서 ‘Add…","html":"<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">해당 글은 \"프론트엔드 최적화 가이드\"라는 도서를 기반하여 작성한 글입니다.</code></pre></div>\n<p>저는 해당 도서에서 제공해주는 샘플코드를 이용하고 있으므로 샘플코드가 없으신분들은 최적화하는 과정에 대해서만 알고계서도 좋을것같습니다.</p>\n<br/>\n<h3 id=\"네트워크-분석\" style=\"position:relative;\"><a href=\"#%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B6%84%EC%84%9D\" aria-label=\"네트워크 분석 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>네트워크 분석</h3>\n<p>네트워크를 확인할 때는 명확한 흐름을 파악할 수 있도록 네트워크에 throttling을 적용합니다. 물론 기본으로 제공되는 ‘Fast 3G’ 나 ‘Slow 3G’ 설정을 적용 할 수 있으나 이번에는 기본 설정보다 조금 더 빠른 환경으로 설정하기 위하여 직접 커스텀 설정을 만들어 보겠습니다.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 296px;\"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 68.58108108108108%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsSAAALEgHS3X78AAADDklEQVQ4yz2TSY/bRhCFeQmQi0+JYWMsidTGVRQpriK1r7N6PNKMNBpMAtiwJzsQBAiCBMhPyB9Kckxyyo/6UmTGPjxUdzX5+tWraqXeaNNqmzRbBsVaHVyjrR+ozV/zNNvzSX7Hp0afyosKDfmm0dQ/oNnSy//eo/hfmS7WmLZL3B8wma+ZTibkScyTjz/Cs1r0A5fQ7xJ4HonfY5ikjPv9EnkUlbnE90nDkNF0gdL1Q3TTwXF9wjgjSgcEyYCnz19QqWlojRZVtU6v4wp5wGI4ZDkashgMyGUfy0Vhp0Mqaz+IUV5tbrjeHTg9vyyVJmnGxeWGhy+/YXO952q7Y3+4ZypEK1E/E6LPDwfu93u+ePOGr96+Zb/ZkMcJsYhRoiQj6Q/Jh1O8XkgYpaIyJ81GpQ3x4zoNpKQkYZplrMbjUulIyh+lkstzYind7QYoYZSwPLlgvjqj6/WEIONye8vJ+SuJe+brM05fbslEQeFVoXAuZDMhGcoFRclRV+D5RGKZko9mpPmYfDRlPFsRJjm6YZflG1anjC3dInC7hK4rzcj4TEreXV1xI4iEMBayUEibMi3K8vic4WTJsSgqlUjpBZFhudKsTrkuoi9N6TkOw7Qvnm05WSy53V6XXQ7krLiwpdsohX++dLpWqVI5qkis0ZTOjkTxbL4kFY/brTYdy8J3OvRlVO52e16ennG8WJTKeqK8OKtWa+Jh0sfJp2jdTNAvobopejTGTGYY8aTMOU4X1+6QiOc32xvu76Tz4ym2aeMLqet6VCxpirHa0YwHqKaPZgeCHprVoyb7muGVeVX2jqETmA2Sri1zZxI4Op5RFzTwdA3XMqnoLkrNCWkKu1ZVUWWAtWKY1QL1/6E15KyCES4xTn/CvfiR0eFXou3P6Mc/oK+/R5e8lZ6LZc9RipdQEKpqA7XeQtUKNB+joKEL4RHt2TuqX/+N9d2f3P72L8Nf/qL67g+0h99Rv/2nJK4cPUMxOx62H2A+jkgBS/x6vy4hZ5bdxXYjzE5AS7wynED24QdYjochT/g/enTGxpBPG3AAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"lazyImage01\"\n        title=\"lazyImage01\"\n        src=\"/static/1c610c02cd63246c0f7b93ec21f1acd4/b1a44/lazyImage01.png\"\n        srcset=\"/static/1c610c02cd63246c0f7b93ec21f1acd4/b1a44/lazyImage01.png 296w\"\n        sizes=\"(max-width: 296px) 100vw, 296px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>throttling 옵션엣서 ‘Add…’를 선택하면 Network Throttling Profiles라는 설정 페이지가 나옵니다. 여기서 ‘Add custom profile…’ 버튼을 눌러 원하는 throttling 옵션을 추가하면 됩니다. 이번에는 ‘6000’이라는 이름으로 다운로드와 업로드 속도를 6000kb/s으로 설정하겠습니다.</p>\n<p>여기서 잠깐 참고하면 Fast 3G의 다운로드 속도는 1500kb/s, 업로드 속도는 750kb/s이며 Slow 3G의 다운로드 속도는 780kb/s, 업로드 속도는 330kb/s입니다.</p>\n<p>이제 이전에 설정하였던 커스텀 옵션으로 throttling을 적용하고 네트워크 분석을 해 봅시다.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 899px;\"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 43.333333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsSAAALEgHS3X78AAAB0ElEQVQoz2WR607bQBCF/SYtxOtdX3Lx3V7fTUgghJICaqWq7/8aX8cI2kr8+DReWXPOmRmnbjrG+ZZ5f2T5XmplW7KienuXdcN0c2B8uMf2A0mak+YlSVaSZsUnnOHmVppL2mEiyQsRv5GmlDAMiaKIYZyEmfYwk50HfD8g3G6JtjGb9Zq1sNn8q85UW2y8Y6zEMfAZhxEryYIgQClFWdU0XU+dJrRjSWw0O+3hax/P8z7hnGzFbbzhrszZG5enoeN0eaEVEaVcGb9hlJSnQNF4K7q1Yd8nDNrFNQajNUaqfq9O1o3s0oxMUi3ui+Dx8ULbdriuCMoE8zQzR4YraVopTfSrpCsi+e+JiH4T+8Cp+pFUdlYshzAel14SPj3TywHc1eqv4D7UqCWFNuSvNX3q43rv6f7DeZFEh92ab03NvaQ4jwO1HGGXyGHWGwoRbMT0LtK03jWdjH0cYqwYuNcK416jP1ArnKfWspcd3hcZ0ybisW045AnWqDeOecqDLWl8D6tXWGkaYoPtEnS1xeQ9plgYMEmN85rHXLYBr9mWc6j4Vef8bkoeQ4+D+sKPIuZnkXDyJZn3laO+4qyuGBvZ4SEnmC7403f8+Rm/OfIHbdEiKaIMpe0AAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"lazyImage02\"\n        title=\"lazyImage02\"\n        src=\"/static/41551f33df3c0e645a8c6cc8eb0479b5/681f1/lazyImage02.png\"\n        srcset=\"/static/41551f33df3c0e645a8c6cc8eb0479b5/5a46d/lazyImage02.png 300w,\n/static/41551f33df3c0e645a8c6cc8eb0479b5/0a47e/lazyImage02.png 600w,\n/static/41551f33df3c0e645a8c6cc8eb0479b5/681f1/lazyImage02.png 899w\"\n        sizes=\"(max-width: 899px) 100vw, 899px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>위 사진에서 보듯이 처음에는 당장 필요한 리소스인 bundle 파일이 다운로드가 되고, 그 다음으로는 빨간색 박스표시가 된 이미지가 다운로드되는 것을 볼 수 있습니다. 그리고 가장 아래에 있는 빨간색 박스를 보면 banner-video 라는 파일인 해당 파일을 보시면 미디어 타입입니다. 그러 해당 banner-video는 페이지에서 가장 처음으로 사용자에게 보이는 콘텐츠인데 가장 나중에 로드되면, 사용자가 첫 화면에서 아무것도 보지 못한 채로 오랫동안 머물게 되므로 사용자 경험에 좋지 않을 겁니다.</p>\n<p>이러한 문제를 해결하는 방법은 위 사진에 보시다시피 동영상의 다운로드를 방해하는 요소 즉, 이미지 다운로드가 끝나고 동영상 다운로드를 시작하니깐 당장 사용되지 않는 이미지를 나중에 다운로드되도록 하여 동영상이 먼저 다운로드되게 하는 것입니다. 다시 말하자면 이미지를 지연 로드하는 것입니다.</p>\n<p>그러면 해당 이미지들을 페이지가 로드될 때 로드하지 않는다면 언제 로드해야 가장 좋은 방법 일까요?</p>\n<p>그 시점은 바로 이미지가 화면에 보이는 순간 또는 그 직전에 이미지를 로드해야 합니다. 다시 말해 뷰포트에 이미지가 표시될 위치까지 스크롤 되었을 때 이미지를 로드할지 말지 판단할 수 있습니다.</p>\n<br/>\n<h3 id=\"intersection-observer\" style=\"position:relative;\"><a href=\"#intersection-observer\" aria-label=\"intersection observer permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Intersection Observer</h3>\n<p>그런데 여기서 하나 문제가 있습니다. 이미지 지연 로딩 작업을 위해 스크롤이 이동했을 때 해당 뷰포트에 이미지를 보이게 할지 판단해야 하는데, 스크롤 이벤트에 이 로직을 넣으면 스크롤할 때마다 해당 로직이 아주 많이 실행된다는 것입니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'스크롤 이벤트 발생!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\">// 스크롤을 조금 움직일때 마다 엄청나게 많은 콜백함수가 실행됩니다.</span>\n<span class=\"token comment\">// 위 코드를 크롬 브라우저에 console 탭에서 입력하고 해당 페이지에서 스크롤을 해보십시오</span></code></pre></div>\n<p>위 코드처럼 스크롤 이벤트를 이용한다면 무거운 로직이 들어가기라도 한다면 브라우저의 메인 스레드에 무리가 갑니다. 성능을 향상시키려다가 오히려 악화시키게 되는 꼴인 거죠. 물론 throtle과 같은 방식으로 처리할 수 있겠지만, 근본적인 해결 방법이 될 수는 없습니다.</p>\n<blockquote>\n<p>throttle은 짧은 시간에 여러 번 발생하는 연산을 일정 시간 동안 한 번만 실행하도록 하는 기술입니다.</p>\n</blockquote>\n<p>이러한 문제를 Intersection Observer를 이용하여 해결할 수 있습니다. Intersection Observer는 브라우저에서 제공하는 API입니다. 이를 통해 웹 페이지의 특정 요소를 관찰하면 페이지 스크롤 시, 해당 요소가 화면에 들어왔는지 아닌지 알려 줍니다. 즉, 스크롤 이벤트처럼 스크롤할 때마다 함수를 호출하는 것이 아니라 요소가 화면에 들어왔을 때만 함수를 호출하는 겁니다. 따라서 성능 면에서 scroll 이벤트로 판단하는 것보다 훨씬 효율적입니다.</p>\n<blockquote>\n<p>Intersection Observer 사용법 : <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API\">https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API</a></p>\n</blockquote>\n<p>Intersection Observer에 대하여 간략한 내용만 살펴보겠습니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> options <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  root<span class=\"token operator\">:</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span>\n  rootMargin<span class=\"token operator\">:</span> <span class=\"token string\">\"0px\"</span><span class=\"token punctuation\">,</span>\n  threshold<span class=\"token operator\">:</span> <span class=\"token number\">1.0</span><span class=\"token punctuation\">.</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">callback</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">entries<span class=\"token punctuation\">,</span> observer</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Entries'</span><span class=\"token punctuation\">,</span> entries<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> observer <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">IntersectonObserver</span><span class=\"token punctuation\">(</span>callback<span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nobserver<span class=\"token punctuation\">.</span><span class=\"token function\">observe</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"#targer-element1\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>options는 Intersection Observer의 옵션입니다.</p>\n<ul>\n<li>root: 대상 객체의 가시성을 확인할 때 사용되는 뷰포트 요소이고, 기본 값은 null 이고, null로 설정 시 브라우저의 뷰포트로 설정됩니다.</li>\n<li>rootMargin: root 요소의 여백, 즉, root의 가시 범위를 가상으로 확장하거나 축소할때 사용됩니다.</li>\n<li>threshold: 가시성 퍼센티지, 대상 요소가 어느 정도로 보일 때 콜백을 실행할지 결정합니다.</li>\n</ul>\n<br/>\n<h3 id=\"intersection-observer-적용하기\" style=\"position:relative;\"><a href=\"#intersection-observer-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0\" aria-label=\"intersection observer 적용하기 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Intersection Observer 적용하기</h3>\n<p>이미지에 Intersection Observer를 활용하여 지연 로딩을 적용해 보겠습니다.</p>\n<p>지금부터는 샘플코드 기반으로 설명 드리오니 샘플코드가 없는 분이시면 해당 내용만 알아 두시면 좋을것 같습니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">function</span> <span class=\"token function\">Card</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> imgRef <span class=\"token operator\">=</span> <span class=\"token function\">useRef</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> options <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">callback</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">entries<span class=\"token punctuation\">,</span> observer</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Entries'</span><span class=\"token punctuation\">,</span> entries<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">const</span> observer <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">IntersectionObserver</span><span class=\"token punctuation\">(</span>callback<span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    observer<span class=\"token punctuation\">.</span><span class=\"token function\">observe</span><span class=\"token punctuation\">(</span>imgRef<span class=\"token punctuation\">.</span>current<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      observer<span class=\"token punctuation\">.</span><span class=\"token function\">disconnect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n\t<span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n\t\t<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Card text-center<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n\t\t\t</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">src</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>props<span class=\"token punctuation\">.</span>image<span class=\"token punctuation\">}</span></span> <span class=\"token attr-name\">ref</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>imgRef<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n\t\t\t</span><span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>중략<span class=\"token operator\">...</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n\t\t</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n\t<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>여기서는 useEffect 안에서 Intersection Observer를 생성하였습니다. 만약 useEffect를 사용하지 않으면 렌더링할 때마다 인스턴스가 생성되고, 대상 요소를 관찰하게 되면서 대상 요소에 여러 개의 콜백이 실행될 것입니다. 따라서 이와 같은 중복을 방지하고자 useEffect에서 인스턴스를 생성해야 합니다. 또한 생성된 인스턴스는 clean-up 함수에서 <code class=\"language-text\">observer.disconnect</code> 함수를 호출함으로써 리소스가 낭비되지 않도록 합니다.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 696px;\"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 30.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsSAAALEgHS3X78AAABEklEQVQY032R0VKDMBBF+yO2BRLYhIQkCNXWoi0y6v//0PUCreOD48OZXdjkZDfZiDFwvoFvAobLiHGaMH184jqOeJ++0MQeeZ5BKY2iUKS85ZqR3zeUqpb6Zrsr8LDNsNsryOML7PMV9jjC9wNSe4BrEg9MMCairDys7WDrCGMjY+D/sOQiiWLBZp8prBSo0hPk8ArTv6EJlNuEUmro0pCaHQilBkpb6CWulKztspxNFatwTmahtCcYdhfbAd53EOu5QRaBUhaVqbk5QIyn2PEQh0oca4J7Y7+ECu5wRuwvHPWCrh2R0hm1D+tolGe5JuUfaNw9P8Kcl9r0JwQ+Qu0iuv7Ih0qUNQsVR5/X/cfs+gZdPrHzWvGq5wAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"lazyImage03\"\n        title=\"lazyImage03\"\n        src=\"/static/2293048ca28ad673bc44f5f7705bcabd/82158/lazyImage03.png\"\n        srcset=\"/static/2293048ca28ad673bc44f5f7705bcabd/5a46d/lazyImage03.png 300w,\n/static/2293048ca28ad673bc44f5f7705bcabd/0a47e/lazyImage03.png 600w,\n/static/2293048ca28ad673bc44f5f7705bcabd/82158/lazyImage03.png 696w\"\n        sizes=\"(max-width: 696px) 100vw, 696px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>이전 코드에서 입력한 console.log 함수에 출력들을 보면 위 사진과 같습니다. entries 값이 배열 형태로 다양한 정보를 담고 있는 것이 보입니다. 이중에서 가장 중요한 값은 바로 <code class=\"language-text\">isIntersecting</code> 이라는 값입니다. 이 값은 해당 요소가 뷰포트 내에 들어왔는지를 나타내는 값입니다. 이 값을 통해 해당 요소가 화면에 보이는 것인지, 화면에서 나가는 것인지 알 수 있습니다.</p>\n<p>이제 다음은 화면에 이미지가 보이는 순간, 즉 콜백이 실행되는 순간에 이미지를 로드하는 일입니다. 이미지 로딩은 img 태그에 src가 할당되는 순간 일어납니다. 따라서 최초에는 img 태그에 src 값을 할당하지 않다가 콜백이 실행되는 순간 src를 할당함으로써 이미지 지연 로딩을 적용할 수 있습니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">function</span> <span class=\"token function\">Card</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> imgRef <span class=\"token operator\">=</span> <span class=\"token function\">useRef</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> options <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">callback</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">entries<span class=\"token punctuation\">,</span> observer</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      entries<span class=\"token punctuation\">.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">entry</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>entry<span class=\"token punctuation\">.</span>isIntersecting<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"is intersecting\"</span><span class=\"token punctuation\">,</span> entry<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>dataset<span class=\"token punctuation\">.</span>src<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          entry<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>src <span class=\"token operator\">=</span> entry<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>dataset<span class=\"token punctuation\">.</span>src<span class=\"token punctuation\">;</span>\n          observer<span class=\"token punctuation\">.</span><span class=\"token function\">unobserve</span><span class=\"token punctuation\">(</span>entry<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">const</span> observer <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">IntersectionObserver</span><span class=\"token punctuation\">(</span>callback<span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    observer<span class=\"token punctuation\">.</span><span class=\"token function\">observe</span><span class=\"token punctuation\">(</span>imgRef<span class=\"token punctuation\">.</span>current<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      observer<span class=\"token punctuation\">.</span><span class=\"token function\">disconnect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n\t<span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n\t\t<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Card text-center<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n\t\t\t</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">data-src</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>props<span class=\"token punctuation\">.</span>image<span class=\"token punctuation\">}</span></span> <span class=\"token attr-name\">ref</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>imgRef<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n\t\t\t</span><span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>중략<span class=\"token operator\">...</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n\t\t</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n\t<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>이전에느 img 태그에 src 속성에 바로 해당 이미지 url를 할당하였지만 위 코드에서는 data-src 라는 속성에 이미지 url을 넣었습니다. 이렇게 하면 src 값이 할당되지 않기 때문에 해당 이미지를 로드 하지 않습니다. 그리고 주소를 data-src 속성에 넣은 이유는 나중에 이미지가 뷰포트에 들어 왔을때, data-src에 있는 값을 src로 옮겨 이미지를 로드하기 위해서입니다.</p>\n<p><code class=\"language-text\">entry.isIntersecting</code> 뷰포트에 해당 이미지가 들어왔을때 <code class=\"language-text\">entry.target.src = entry.target.dataset.src</code> 이미지 src 속성에 이미지 url을 할당합니다. 그리고 한 번 이미지를 로드한 후에는 다시 호출할 필요가 없으므로 <code class=\"language-text\">observer.unobserve(entry.target)</code> ‘unobserve’ 메서드를 이용하여 해제합니다.</p>\n<p>이제 정리하면, 개발자 도구 Network 패널을 확인해보면 최초 페이지 로딩 시에는 해당 이미지가 로드되지 않고 있다가 스크롤이 해당 이미지 영역에 도달하면 이미지가 로드되는 것을 확인 할 수 있습니다. 즉, 최초 페이지 로딩 시에는 보이지 않는 이미지가 우선순위가 높은 콘텐츠(동영상)의 로딩을 방해하지 않고 나중에 필요할 때 로드되는 것입니다.</p>\n<br/>","frontmatter":{"title":"이미지 지연 로딩","date":"August 08, 2023"}}},"pageContext":{"slug":"/frontendPerformance/lazyImagLoad/","previous":{"fields":{"slug":"/algorithm/leetcode/15/"},"frontmatter":{"title":"leetcode - 3Sum"}},"next":{"fields":{"slug":"/frontendPerformance/imagsSize/"},"frontmatter":{"title":"이미지 사이즈 최적화"}}}}}