<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>CS겸 취준까지</title>
    <link>https://together-cs.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 16 Aug 2026 17:03:16 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>H.E</managingEditor>
    <image>
      <title>CS겸 취준까지</title>
      <url>https://tistory1.daumcdn.net/tistory/6415335/attach/648d1e5fa1af4814a2d778d3b8a9547e</url>
      <link>https://together-cs.tistory.com</link>
    </image>
    <item>
      <title>Proxy(Object.defineProperty와 비교)</title>
      <link>https://together-cs.tistory.com/138</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;프록시(Proxy)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Proxy는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;특정 객체를 감싸&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;프로퍼티 읽기, 쓰기와 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;객체에 가해지는 작업&lt;/b&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중간에서 가로채는 객체&lt;/b&gt;로,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;가로채진 작업&lt;/b&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Proxy 자체에서 처리&lt;/b&gt;되기도 하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;원래 객체가 처리하도록 그대로 전달&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;되기도 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Proxy의 사전적 뜻은 '대리인', '대리'라는 뜻으로 자바스크립트에서도 대리인의 역할을 수행함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;i&gt;&lt;b&gt;프록시 객체(Proxy object)&lt;/b&gt;&lt;/i&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;대상 객체(Target object) 대신 사용&lt;/b&gt;됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대상 객체를 직접 사용하는 대신, 프록시 객체가 사용되며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;각 작업을 대상 객체로 전달하고 결과 다시 코드로 돌려줌&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMKrHs/btsHXtZvkye/ihk3LpvDOdeSU27g4nyXjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMKrHs/btsHXtZvkye/ihk3LpvDOdeSU27g4nyXjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMKrHs/btsHXtZvkye/ihk3LpvDOdeSU27g4nyXjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMKrHs%2FbtsHXtZvkye%2Fihk3LpvDOdeSU27g4nyXjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;635&quot; height=&quot;172&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이러한 방식을 통해 프록시 객체는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자바스크립트의 기본적인 명령에 대한 동작&lt;/b&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용자 정의 가능&lt;/b&gt;하도록 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;객체 자체가 처리하는 특정 명령을 정의&lt;/b&gt;할 수 있게 되는 것&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런 명령의 종류는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;속성검색, 접근, 할당, 열거, 함수 호출&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등이 대표적&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ Proxy 사용법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1718192593919&quot; class=&quot;javascript&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 대상 객체(Real Subject)
let target = { ... }

// target의 동작을 가로채어 제어하는 미리 정의된 메서드 내부를 구현한 핸들러
let handler = {
    get(target, prop) { ... },
    set(target, prop, value) { ... },
    ...
}

// 프록시 생성 및 등록
const proxy = new Proxy(target, handler)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프록시 객체를 생성하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;new를 붙여 생성자를 호출&lt;/b&gt;해야 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Proxy는 필수적으로 2개의 인자를 받음&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;target : Proxy의 대상이 되는 객체(감싸질 객체, 함수를 포함한 모든 객체가 가능)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;handler : target의 동작을 제어하는 메서드를 정의한 객체(get, set 등 메서드를 정의한 것을 볼 수 있는데 이 메서드들은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;target 객체의 동작을 중간에 가로채서 제어 로직을 가미하게 하는 미리 정의된 메서드&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;&lt;b&gt;트랩(trap)&lt;/b&gt;&lt;/i&gt;이라고 부름)&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ex) get 트랩은 target의 프로퍼티를 읽을 때, set 트랩은 target의 프로퍼티를 쓸 때 활성화됨&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;proxy에 작업이 가해지고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;handler에 작업과 상응하는 트랩&lt;/b&gt;이 있으면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;트랩이 실행&lt;/b&gt;되어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;프록시가 이 작업을 처리할 기회를 얻게 됨&lt;/b&gt;(&lt;b&gt;트랩이 없으면&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;target에 작업이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;직접 수행&lt;/b&gt;됨)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Proxy 예제&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1718192593920&quot; class=&quot;qml&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 대상 객체 (target)
const user = {
    firstName: 'John',
    lastName: 'Doe',
    email: 'john.doe@example.com',
}

// 핸들러 (handler)
const handler = {
	// 대상 객체에 프로퍼티 값을 할당하려는 동작(get)을 가로채어 실행
    get(target, property) {
        console.log(`Property ${property} has been read.`);
        return target[property];
    }
}

const proxyUser = new Proxy(user, handler);

console.log(proxyUser.firstName);
// Property firstName has been read
// John&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이때 주의할점은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;클라이언트&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;프록시 객체&lt;/b&gt;인 proxyUser를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;통해 접근&lt;/b&gt;해야 된다는 점&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UJrgr/btsHW9Ha8b3/tDxT4in3vOdZNGcpazcrk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UJrgr/btsHW9Ha8b3/tDxT4in3vOdZNGcpazcrk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UJrgr/btsHW9Ha8b3/tDxT4in3vOdZNGcpazcrk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUJrgr%2FbtsHW9Ha8b3%2FtDxT4in3vOdZNGcpazcrk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;638&quot; height=&quot;250&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;user 객체를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;프록시 객체가 감싸고 있는 형태&lt;/b&gt;이기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;외부 포장과 같은 프록시를 통해 대상 객체&lt;/b&gt;인 user와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;통신&lt;/b&gt;하게 되기 때문(콘솔 로그를 실행하면 원래는 값만 나와야 되는것이 다음과 같이 추가적으로 코드(콘솔)가 가미됨을 볼 수 있음)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Proxy 트랩 핸들러 종류&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;table style=&quot;color: #666666; text-align: center; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style13&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #6ed3d8; color: #ffffff; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;Property 가로채는&lt;/b&gt;&amp;nbsp;트랩&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #6ed3d8; color: #ffffff; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;작동 시점&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;get&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로퍼티를 읽을 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;set&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;프로퍼티에 값을 쓸 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;has&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;in 연산자가 작동할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;deleteProerty&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;delete 연산자가 작동할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;color: #666666; text-align: center; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style13&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #6ed3d8; color: #ffffff; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Method 가로채는 트랩&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #6ed3d8; color: #ffffff; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;작동 시점&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;apply&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;함수를 호출할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;constructor&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;new 연산자가 작동할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;color: #666666; text-align: center; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style13&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #6ed3d8; color: #ffffff; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Object 가로채는&amp;nbsp;&lt;b&gt;트랩&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #6ed3d8; color: #ffffff; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;작동 시점&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;Object.getPrototypeOf 작동할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;setPrototypeOf&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;Object.setPrototypeOf 작동할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;isExtensible&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;Object.isExtensible 작동할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;preventExtensions&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;Object.preventExtensions 작동할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;getOwnPropertyDescriptor&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;Object.getOwnPropertyDescriptor 작동할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;ownKeys&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Object.getOwnPropertyNames 작동할 때&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Object.getOwnPropertySymbols 작동할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ Proxy 해제하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쓸모없어진 프록시 객체를 해체하여 메모리 측면에서 여유공간을 얻고싶다면 Proxy를 해제하면 됨&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Proxy 객체의 Target 원본 객체를 null로 해버리면 자동으로 해체될것 같아 보이지만 반영되지 않음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;따라서 직접&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;명시적으로 프록시 객체를 제거&lt;/b&gt;할 필요가 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프록시를 해지하지 위해선, 처음 부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;&lt;b&gt;취소 가능 프록시(Revocable Proxy)&lt;/b&gt;&lt;/i&gt;&lt;b&gt;로 정의&lt;/b&gt;할 필요가 있는데,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;&lt;b&gt;Proxy.revocable()&lt;/b&gt;&lt;/i&gt;를 통해 얻을 수 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;&lt;b&gt;revoke&lt;/b&gt;&lt;/i&gt;를 이용해서 Target 객체를 참조하던&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Proxy 객체를 해제&lt;/b&gt;할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1718192593923&quot; class=&quot;pgsql&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;let obj = {
    name: '홍길동',
};

let handler = {
    get(target, key) {},
    set(target, key, value) {},
};

// 취소 가능한 프록시 객체를 구조분해로 얻기
const { proxy, revoke } = Proxy.revocable(obj, handler);

try {
    revoke(); // 프록시 해제
    proxy.name = &quot;임꺽정&quot;; // !프록시 사용 불가
} catch (err) {
    console.error(err.message); // Cannot perform 'set' on a proxy that has been revoked
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ Proxy를 사용하는 이유&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;객체에 어떤 작업을 할 땐 자바스크립트 명세서에 정의된 '내부메서드'가 깊숙한 곳에서 관여함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로퍼티를 읽을 땐 [[Get]]이라는 내부 메서드가, 프로퍼티에 쓸 땐 [[Set]]이라는 내부 메서드가 관여하게 됨&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런 내부 메서드들은 명세서에만 정의된 메서드이기 때문에 개발자가 코드를 사용해 호출할 순 없음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;프록시 기능 활성화 예제(get 가로채기)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1718192593923&quot; class=&quot;javascript&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;let numbers = [0, 1, 2];

numbers = new Proxy(numbers, {
  get(target, prop) {
    if (prop in target) {
      return target[prop];
    } else {
      return 0; // 기본값
    }
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;객체에 없는 프로퍼티를 호출했을 때, undefined가 아닌 0이 출력&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바스크립트의 내부 메서드 GET을 통해, 객체에 없는 프로퍼티를 읽으면 undefined가 출력되게 되어있음&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만, 프록시로 0이 출력되도록 한 것&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이것이 프록시의 기능&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Proxy와 Object.defineProperty&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ Object.defineProperty&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Object.defineProperty()는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;JavaScript에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;객체의 프로퍼티를 정의 또는 수정하는 메서드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;메서드를 사용하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;객체에 새로운 프로퍼티를&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;추가&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;하거나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기존 프로퍼티의&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;속성을 변경&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;할 수 있음&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;즉, 객체에 새로운 속성을 직접 정의하거나 이미 존재하는 속성을 수정한 후 해당 객체를 반환함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;defineproperty-인수&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;defineProperty 인수&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1718192593924&quot; class=&quot;reasonml&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;Object.defineProperty(obj, prop, descriptor);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1718192593924&quot; class=&quot;yaml&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const person = {};
Object.defineProperty(person, 'firstName', {
	value: 'Ungmo',
  	writable: true,
  	enumerable: true,
  	configurable: true
}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;obj: 속성을 정의할 객체(반환값으로 obj 객체를 반환함)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;prop : 새로 정의하거나 수정하려는 속성의 이름 또는 Symobl&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;descriptor: 새로 정의하거나 수정하려는 속성을 기술하는 객체&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;value(속성값) : undefined&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;get(속성 접근자 함수) : undefined&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;set(속성 설정자 함수): undefined&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;writable(속성의 값 변경 가능 여부) : false&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;enumerable(열거 가능 여부) : false&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;configurable(속성 값 변경/삭제 여부) : false&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;- [value, writable]과 [get, set]은 동시에 사용할 수 없음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;즉, [value, writable] 중 하나(또는 전체)와 [get, set] 중 하나(또는 전체)를 함께 사용할 수 없음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;color: #666666; text-align: center; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style13&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #6ed3d8; color: #ffffff; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특징&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #6ed3d8; color: #ffffff; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Proxy&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #6ed3d8; color: #ffffff; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Object.defineProperty&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;문법&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;new Proxy(target, handler)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Object.defineProperty(obj, prop, desc)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;유형&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메타 프로그래밍 도구&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;속성 설명자 도구&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;호환성&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ES6 이상&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ES5 이상&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;직접적 상호작용&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대상에 대한 모든 작업을 가로챔&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;객체의 단일 속성에만 영향을 줌&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;전체 객체의 동작 수정&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단일 속성의 동작 수정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;성능&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가로채리고 인한 일반적으로 느림&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;직접 속성을 수정하므로 더 빠름&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;확장성&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;동작에 대한 세부적인 제어 제공&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기본 속성 설명자로 제한됨&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #dcdddd; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용 사례&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;고급 객체 조작, 유효성 검사&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f0f0f0; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특정 동작을 가진 새로운 속성 추가&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 메타 프로그래밍: 프로그램이나 언어를 조작하는 것을 의미&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;메타 프로그래밍 도구는 프로그램의 동작이나 구조를 변경하고 확장하기 위해 사용되는 도구들을 가리킴&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Proxy를 사용하면 객체의 동작을 가로채거나 수정하여 객체에 대한 접근을 제어하거나 변경 이를 통해 객체의 동작을 수정하거나 확장하여 메타 프로그래밍 작업을 수행할 수 있음&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://velog.io/@falling_star3/JS-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-Proxy&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;[JS]&amp;nbsp;자바스크립트의&amp;nbsp;Proxy&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Proxy-Reflect-%EA%B3%A0%EA%B8%89-%EA%B8%B0%EB%B2%95#javascript_reflect_%EA%B0%9D%EC%B2%B4&quot;&gt;자바스크립트&amp;nbsp;Proxy&amp;nbsp;&amp;amp;&amp;nbsp;Reflect&amp;nbsp;고급&amp;nbsp;기법&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty&quot;&gt;Object.defineProperty()&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://velog.io/@boyeon_jeong/%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-%EC%A0%95%EC%9D%98object.definedProperty-%EB%A7%88%EC%8A%A4%ED%84%B0-%ED%95%98%EA%B8%B0&quot;&gt;프로퍼티&amp;nbsp;정의(object.defineProperty)&amp;nbsp;마스터&amp;nbsp;하기&lt;/a&gt;&lt;/p&gt;</description>
      <category>CS/프로그래밍</category>
      <author>H.E</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/138</guid>
      <comments>https://together-cs.tistory.com/138#entry138comment</comments>
      <pubDate>Wed, 12 Jun 2024 20:43:21 +0900</pubDate>
    </item>
    <item>
      <title>정규화(Normalization)</title>
      <link>https://together-cs.tistory.com/137</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;정규화 란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화는 관계형 데이터베이스에서 데이터를 구조화하고 중복을 줄이며 데이터의 일관성을 유지하기 위한 과정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 데이터베이스의 성능을 향상시키고 데이터의 무결성을 확보할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화는 주로 엔티티 간의 관계를 분석하여 데이터를 논리적인 단위로 나누는 작업이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화의 기본 목표는 테이블 간에 중복된 데이터를 허용하지 않는다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복된 데이터를 허용하지 않음으로써 무결성을 유지할 수 있으며, DB용량 역시 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정규화 단계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화는 여러 단계로 진행되며, 각 단계는 정규형(Normal Form)이라고 불리는 기준을 충족해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 정규형은 데이터의 구조를 조금씩 변경하여 중복과 종속성을 제거하며, 더욱 높은 수준의 일관성을 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제 1 정규화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 1 정규화란 테이블의 컬럼이 원자값(Atomic Value, 하나의 값)을 갖도록 테이블을 분해하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 아래와 같은 고객 취미 테이블이 존재한다고 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lDCtJ/btsHVHrxwtJ/sYN4JZkB2dczBMt1gfnpI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lDCtJ/btsHVHrxwtJ/sYN4JZkB2dczBMt1gfnpI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lDCtJ/btsHVHrxwtJ/sYN4JZkB2dczBMt1gfnpI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlDCtJ%2FbtsHVHrxwtJ%2FsYN4JZkB2dczBMt1gfnpI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;324&quot; height=&quot;301&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 테이블에서 추신수와 박세리는 여러 개의 취미를 가지고 있기 때문에 제 1 정규형을 만족하지 못하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 이를 제 1 정규화하여 분해할 수 있다. 제 1 정규화를 진행한 테이블은 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;255&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P0MSi/btsHWTkhXBk/7BsHD3i8ywK4UFbc09Mfik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P0MSi/btsHWTkhXBk/7BsHD3i8ywK4UFbc09Mfik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P0MSi/btsHWTkhXBk/7BsHD3i8ywK4UFbc09Mfik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP0MSi%2FbtsHWTkhXBk%2F7BsHD3i8ywK4UFbc09Mfik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;255&quot; height=&quot;388&quot; data-origin-width=&quot;255&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제 2 정규화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 2 정규화란 제 1 정규화를 진행한 테이블에 대해 완전 함수 종속을 만족하도록 테이블을 분해하는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1718188327300&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  Info. 완전 함수 종속 : 완전 함수 종속이라는 것은 기본키의 부분집합이 결정자가 되어선 안된다는 것을 의미한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 아래와 같은 수강 강좌 테이블을 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;989&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MXypJ/btsHWA6m9g1/eMkDyl3cVTnQVdGcRkN9WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MXypJ/btsHWA6m9g1/eMkDyl3cVTnQVdGcRkN9WK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MXypJ/btsHWA6m9g1/eMkDyl3cVTnQVdGcRkN9WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMXypJ%2FbtsHWA6m9g1%2FeMkDyl3cVTnQVdGcRkN9WK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;989&quot; height=&quot;266&quot; data-origin-width=&quot;989&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 테이블에서 기본키는 (학생번호, 강좌이름)으로 복합키이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 (학생번호, 강좌이름)인 기본키는 성적을 결정하고 있다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;(학생번호, 강좌이름) --&amp;gt; (성적)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 여기서 강의실이라는 컬럼은 기본키의 부분집합인 강좌이름에 의해 결정될 수 있다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;(강좌이름) --&amp;gt; (강의실)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 기본키(학생번호, 강좌이름)의 부분키인 강좌이름이 결정자이기 때문에 위의 테이블의 경우 아래와 같이 기존의 테이블에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강의실을 분해하여 별도의 테이블로 관리하여 제 2 정규형을 만족시킬 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;473&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chWzIE/btsHVDW0WlO/7xp3RRktetaYODmBz3gtm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chWzIE/btsHVDW0WlO/7xp3RRktetaYODmBz3gtm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chWzIE/btsHVDW0WlO/7xp3RRktetaYODmBz3gtm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchWzIE%2FbtsHVDW0WlO%2F7xp3RRktetaYODmBz3gtm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;828&quot; height=&quot;473&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;473&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제 3 정규화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 3 정규화란 제 2 정규화를 진행한 테이블에 대해 이행적 종속을 없애도록 테이블을 분해한 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1718188353112&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  Info. 이행적 종속 A &amp;rarr; B, B &amp;rarr; C가 성립할 때 A&amp;rarr; C가 성립되는 것을 의미한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 아래와 같은 계절 학기 테이블을 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MScdi/btsHW7buUiL/ce0jXMPOXY5VfuCQtLtIYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MScdi/btsHW7buUiL/ce0jXMPOXY5VfuCQtLtIYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MScdi/btsHW7buUiL/ce0jXMPOXY5VfuCQtLtIYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMScdi%2FbtsHW7buUiL%2Fce0jXMPOXY5VfuCQtLtIYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;952&quot; height=&quot;246&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 테이블에서 학생 번호는 강좌 이름을 결정하고 있고, 강좌 이름은 수강료를 결정하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 이를 (학생 번호, 강좌 이름)테이블과 (강좌 이름, 수강료)테이블로 분해해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이행적 종속을 제거하는 이유는 비교적 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 501번 학생이 수강하는 강좌가 스포츠경영학으로 변경되었다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이행적 종속이 존재한다면 501번 학생은 스포츠경영학이라는 수업을 20,000원이라는 수강료로 듣게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 강좌 이름에 맞게 수강료를 다시 변경할 수 있지만, 이러한 번거로움을 해결하기 위해 제 3 정규화를 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 학생 번호를 통해 강좌 이름을 참조하고, 강좌 이름으로 수강료를 참조하도록 테이블을 분해해야 하며 그 결과는 아래 그림과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boOsuz/btsHVIKNcRD/Nb8dZkoapervYISOkUf1m1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boOsuz/btsHVIKNcRD/Nb8dZkoapervYISOkUf1m1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boOsuz/btsHVIKNcRD/Nb8dZkoapervYISOkUf1m1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboOsuz%2FbtsHVIKNcRD%2FNb8dZkoapervYISOkUf1m1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;668&quot; height=&quot;329&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>하계동물고기</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/137</guid>
      <comments>https://together-cs.tistory.com/137#entry137comment</comments>
      <pubDate>Wed, 12 Jun 2024 19:36:11 +0900</pubDate>
    </item>
    <item>
      <title>브라우저 살펴보기 - 컴포지터가 사용자 입력을 받았을 때(3)</title>
      <link>https://together-cs.tistory.com/134</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;기술글을 보고 정리하였음(&lt;a href=&quot;https://d2.naver.com/helloworld/6204533&quot;&gt;https://d2.naver.com/helloworld/6204533&lt;/a&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;이 글은 사용자 입력(input)을 받았을 때 컴포지터가 어떻게 부드러운 상호작용이 이루어지게 하는지 알아보고 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기술글이 2019년도에 작성된 글이기 때문에 현재와는 많이 다른점이 있을것이기에 이런 흐름으로 만들어졌다고 이해하고 현재와 다른점이 있다는것을 생각하면서 봐야함(크롬에 많은 버전 업데이트가 있었기 때문)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;컴포지터가&amp;nbsp;사용자&amp;nbsp;입력을&amp;nbsp;받았을&amp;nbsp;때&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 브라우저 관점에서 입력 이벤트&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;'입력 이벤트(input event)'&lt;/b&gt;라는 말을 들었을 때 입력란에서 일어나는 값 입력이나 마우스 클릭만 생각할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저의 관점에서 입력이란 모든 사용자의 제스처&lt;/b&gt;를 의미&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마우스 휠을 스크롤하는 것도 입력 이벤트이고, 화면을 터치하거나 마우스 포인터를 화면 위에 올리는 것도 입력 이벤트 해당&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ei0GGg/btsHSdiYZ2W/W8XzF9NEvQNx89OnaOKqL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ei0GGg/btsHSdiYZ2W/W8XzF9NEvQNx89OnaOKqL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ei0GGg/btsHSdiYZ2W/W8XzF9NEvQNx89OnaOKqL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fei0GGg%2FbtsHSdiYZ2W%2FW8XzF9NEvQNx89OnaOKqL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;565&quot; height=&quot;284&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;브라우저 프로세스를 통해 렌더러 프로세스(Renderer Process)로 라우팅되는 입력 이벤트&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/2JcG8/btsHODhI4yu/IK8rA0hlYuQeJaRq4Q83lK/img.png&quot;&gt;&lt;/span&gt;브라우저 프로세스를 통해 렌더러 프로세스(Renderer Process)로 라우팅되는 입력 이벤트&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;화면 터치와 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용자 제스처가 발생&lt;/b&gt;했을 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가장 먼저 제스처를 수신&lt;/b&gt;하는 것은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;브라우저 프로세스&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;제스처가 어디에서 발생했는지만 알고 있음&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;탭 내부의 콘텐츠는 렌더러 프로세스가 처리해야 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트 유형(예: touchstart )&lt;/b&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트가 발생한 좌표&lt;/b&gt;를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;렌더러 프로세스로 보냄&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;렌더러 프로세스&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트 대상을 찾고&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;해당 대상과 연결된 이벤트 리스너를 실행해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트&lt;/b&gt;를 적절하게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;처리&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 컴포지터는 입력 이벤트를 받는다&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹 페이지에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트 리스너가 연결되어 있지 않으면&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드와 상관없이&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;새로운 합성 프레임&lt;/b&gt;을 만들 수 있음 하지만 이벤트 리스너가 웹 페이지에 연결되어 있다면, 이벤트를 처리해야 하는지 컴포지터 스레드가 어떻게 알 수 있을까?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 고속 스크롤 불가 영역의 이해&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCZx1k/btsHR1iUVYD/hQBGYpuzIKZdssbhxwQQvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCZx1k/btsHR1iUVYD/hQBGYpuzIKZdssbhxwQQvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCZx1k/btsHR1iUVYD/hQBGYpuzIKZdssbhxwQQvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCZx1k%2FbtsHR1iUVYD%2FhQBGYpuzIKZdssbhxwQQvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;561&quot; height=&quot;313&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;고속 스크롤 불가 영역에서 발생한 입력 이벤트를 설명하는 다이어그램&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/zSKAb/btsHO0cwESL/g1VZea4kO0qD9f81hi8Fu1/img.png&quot;&gt;&lt;/span&gt;고속 스크롤 불가 영역에서 발생한 입력 이벤트를 설명하는 다이어그램&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;JavaScript 실행&lt;/b&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드의 작업&lt;/b&gt;이므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;웹 페이지가 합성될 때 컴포지터 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트 핸들러가 연결된 영역&lt;/b&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'고속 스크롤 불가 영역(non-fast scrollable region)'&lt;/b&gt;이라고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;표시&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹 페이지의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이 영역에서 이벤트가 발생&lt;/b&gt;했을 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;입력 이벤트&lt;/b&gt;를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드로 보내야 하는지&lt;/b&gt;를 이 정보로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;확인&lt;/b&gt;할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;입력 이벤트&lt;/b&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;고속 스크롤 불가 영역 밖에서 발생&lt;/b&gt;했다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드를 기다리지 않고 새 프레임을 합성&lt;/b&gt;(&lt;span style=&quot;text-align: start;&quot;&gt;컴포지터 스레드가 메인 스레드를 기다리지 않을 수 있는 이유는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;컴포지터 스레드가 메인 스레드의 레이어 트리를 복사해서 별도로 가지고 있기 때문&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 이벤트 핸들러를 작성할 때 주의한다&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹&amp;nbsp;개발에서&amp;nbsp;이벤트를&amp;nbsp;처리하는&amp;nbsp;흔한&amp;nbsp;패턴은&amp;nbsp;&lt;b&gt;이벤트&amp;nbsp;위임(event&amp;nbsp;delegation)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;이벤트 버블링&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;덕분에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;하나의 이벤트 핸들러를 최상위 요소에 연결&lt;/b&gt;하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트 대상을 고려해 처리를 위임&lt;/b&gt;할 수 있음&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfY1Md/btsHSvRcpVz/oYVSF8Qb7E0BWeLvDY1BAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfY1Md/btsHSvRcpVz/oYVSF8Qb7E0BWeLvDY1BAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfY1Md/btsHSvRcpVz/oYVSF8Qb7E0BWeLvDY1BAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfY1Md%2FbtsHSvRcpVz%2FoYVSF8Qb7E0BWeLvDY1BAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;654&quot; height=&quot;365&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;전체 웹 페이지가 고속 스크롤 불가 영역일 때 입력 이벤트의 처리를 설명하는 다이어그램&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/buybpJ/btsHPhkFI61/0XFNSBNhnNYhWz81g9Hrr1/img.png&quot;&gt;&lt;/span&gt;전체 웹 페이지가 고속 스크롤 불가 영역일 때 입력 이벤트의 처리를 설명하는 다이어그램&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;모든 요소에 대해 이벤트 핸들러를 하나만 작성하면 되므로 이런 이벤트 위임 패턴이 무척이나 편해 보이지만 브라우저의 관점에서 이 코드(body에서 이벤트 처리)를 보면 이제&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;웹 페이지의 모든 영역이 고속 스크롤 불가 영역&lt;/b&gt;으로 표시됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;애플리케이션이 신경 쓰지 않는 부분에 입력&lt;/b&gt;이 들어와도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;입력 이벤트가 들어올 때마다 메인 스레드와 통신&lt;/b&gt;해야 하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드가 일을 끝내기를 기다려야 함&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;그래서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터가 스크롤을 부드럽게 할 수 없게 됨&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;이런&amp;nbsp;&lt;b&gt;문제를&amp;nbsp;방지&lt;/b&gt;하기&amp;nbsp;위해&amp;nbsp;&lt;b&gt;이벤트&amp;nbsp;리스너&lt;/b&gt;에서&amp;nbsp;&lt;b&gt;passive: true 옵션&lt;/b&gt;을 전달&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여전히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인&amp;nbsp;스레드에서&amp;nbsp;이벤트를&amp;nbsp;받지만&lt;/b&gt;&amp;nbsp;&lt;b&gt;컴포지터가&amp;nbsp;메인&amp;nbsp;스레드의&amp;nbsp;처리를&amp;nbsp;기다리지&amp;nbsp;않고&amp;nbsp;새&amp;nbsp;프레임을&amp;nbsp;만들어도&amp;nbsp;된다는&amp;nbsp;힌트&lt;/b&gt;를 브라우저에 주는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;옵션&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717847647868&quot; class=&quot;cs&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;document.body.addEventListener('touchstart', event =&amp;gt; {  
    if (event.target === area) {
        event.preventDefault();
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1717847647869&quot; class=&quot;cs&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;document.body.addEventListener('touchstart', event =&amp;gt; {  
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 이벤트를 취소할 수 있는지 확인한다&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pQJRM/btsHRKoagG3/HewRodG4pNADZ8K3pcm3A1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pQJRM/btsHRKoagG3/HewRodG4pNADZ8K3pcm3A1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pQJRM/btsHRKoagG3/HewRodG4pNADZ8K3pcm3A1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpQJRM%2FbtsHRKoagG3%2FHewRodG4pNADZ8K3pcm3A1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;368&quot; height=&quot;230&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;가로 스크롤만 가능한 영역이 있는 웹 페이지&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/0gOPH/btsHOix5Hud/n1XO2uCKELfRgVo1efAy10/img.png&quot;&gt;&lt;/span&gt;가로 스크롤만 가능한 영역이 있는 웹 페이지&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;어떤 박스 영역의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;스크롤 방향을 가로로만 제한&lt;/b&gt;하고 싶은 경우&lt;br /&gt;&lt;br /&gt;&lt;b&gt;포인터 이벤트&lt;/b&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;passive: true 옵션을 사용하면 부드럽게 스크롤됨&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만 스크롤 방향을 제한하기 위해 preventDefault() 메서드를 호출하기 전에 이미 수직 스크롤이 시작되었을 수도 있음 event.cancelable() 메서드(이벤트위 취소가 가능한지 나타냄)를 사용하면 수직 스크롤 시작 여부를 확인할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717847647869&quot; class=&quot;cs&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;document.body.addEventListener('pointermove', event =&amp;gt; {  
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /*
        *  do what you want the application to do here
        */
    }
}, {passive: true});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;또는 touch-action과 같은 CSS 규칙을 사용해 이벤트 핸들러를 아예 안 쓸 수도 있음&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717847647869&quot; class=&quot;css&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;#area {
  touch-action: pan-x;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 이벤트 대상 찾기&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDIFBx/btsHSamnBIx/KEkVg14KasuWI5pxoAZpFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDIFBx/btsHSamnBIx/KEkVg14KasuWI5pxoAZpFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDIFBx/btsHSamnBIx/KEkVg14KasuWI5pxoAZpFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDIFBx%2FbtsHSamnBIx%2FKEkVg14KasuWI5pxoAZpFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;290&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;x, y 지점에 무엇이 그려졌는지 확인하기 위해 페인트 기록을 보는 메인 스레드&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bYUEvB/btsHPg0muKX/WSoKfGjLG4hpH96ckOr2Gk/img.png&quot;&gt;&lt;/span&gt;x, y 지점에 무엇이 그려졌는지 확인하기 위해 페인트 기록을 보는 메인 스레드&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;b&gt;컴포지터&amp;nbsp;스레드&lt;/b&gt;가&amp;nbsp;&lt;b&gt;입력&amp;nbsp;이벤트&lt;/b&gt;를&amp;nbsp;&lt;b&gt;메인&amp;nbsp;스레드로&amp;nbsp;보낼&amp;nbsp;때&amp;nbsp;가장&amp;nbsp;먼저&amp;nbsp;하는&amp;nbsp;일&lt;/b&gt;은&amp;nbsp;&lt;b&gt;이벤트 대상을 찾는 히트 테스트(hit test)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;이벤트가 발생한 좌표에 무엇이 있는지 확인&lt;/b&gt;하기 위해 히트 테스트는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;렌더링 프로세스에서 생성된 페인트 기록의 데이터를 사용&lt;/b&gt;( clip&lt;span style=&quot;text-align: start;&quot;&gt;,&amp;nbsp;&lt;/span&gt;opacity&lt;span style=&quot;text-align: start;&quot;&gt;,&amp;nbsp;&lt;/span&gt;transform&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;등의 속성을 반영해야 이벤트 대상을 정확히 알 수 있기 때문인것으로 보임&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 메인 스레드로 이벤트를 전송하는 것을 최소화하기&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;일반적인 디스플레이 장치&lt;/b&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;화면을 초당 60번 새로 갱신&lt;/b&gt;하며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;애니메이션을 화면 갱신 주기에 맞춰야 부드럽게 움직임&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;입력의 경우&lt;/b&gt;에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;일반적인 터치스크린 장치&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;터치 이벤트를 초당 60~120회 전달&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마우스는 이벤트를 초당 100회 전달.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;입력 이벤트의 전달 주기가 화면 갱신 주기보다 짧음&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpmx1M/btsHS8ny4lM/jXsnbara1ubuC9iPukHrn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpmx1M/btsHS8ny4lM/jXsnbara1ubuC9iPukHrn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpmx1M/btsHS8ny4lM/jXsnbara1ubuC9iPukHrn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcpmx1M%2FbtsHS8ny4lM%2FjXsnbara1ubuC9iPukHrn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;691&quot; height=&quot;168&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;웹 페이지의 애니메이션 타임 라인에 넘쳐나 버벅거림을 유발하는 이벤트&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/znAIM/btsHOCiNoFx/dXopeHwmX1cHh5x6UMC87K/img.png&quot;&gt;&lt;/span&gt;웹 페이지의 애니메이션 타임 라인에 넘쳐나 버벅거림을 유발하는 이벤트&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;touchmove 이벤트(하나 이상의 터치 포인터가 터치 표면을 따라 이동하면 이벤트 시작)처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;연속적인 이벤트가 초당 120회씩 메인 스레드로 보내지면 화면이 갱신되는 정도보다 훨씬 많이 히트 테스트&lt;/b&gt;를 하거나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JavaScript를 실행&lt;/b&gt;할 수도 있음&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tKQir/btsHS1ISboD/EEsmG4lWJnCayLKYT8I2zK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tKQir/btsHS1ISboD/EEsmG4lWJnCayLKYT8I2zK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tKQir/btsHS1ISboD/EEsmG4lWJnCayLKYT8I2zK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtKQir%2FbtsHS1ISboD%2FEEsmG4lWJnCayLKYT8I2zK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;605&quot; height=&quot;178&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;376&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;이전과 같은 타임 라인에서 합쳐지고 지연된 이벤트&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bdcsSI/btsHOGSVfkw/oknBkykJ87p4GJFsryIhk0/img.png&quot;&gt;&lt;/span&gt;이전과 같은 타임 라인에서 합쳐지고 지연된 이벤트&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;메인 스레드&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;호출이 과도해지는 것을 막기 위해&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Chrome은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;연속적인 이벤트&lt;/b&gt;(예를 들어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;wheel , mousewheel , mousemove , pointermove , touchmove&lt;/i&gt;)를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;합쳐서&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다음번 requestAnimationFrame() 메서드 실행 직전까지 전송(dispatch)하지 않고 기다림&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;keydown,&amp;nbsp;keyup,&amp;nbsp;mouseup,&amp;nbsp;mousedown,&amp;nbsp;touchstart,&amp;nbsp;touchend와&amp;nbsp;같은&amp;nbsp;&lt;b&gt;비연속적인(discrete) 이벤트는 즉시 전달&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 한 프레임 안에서 합쳐진 이벤트(intra-frame events)를 얻으려면 getCoalescedEvents() 메서드를 사용한다&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhoeRZ/btsHSYZFJ9p/LZD3ZeBJfk5QXvKr99Xi11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhoeRZ/btsHSYZFJ9p/LZD3ZeBJfk5QXvKr99Xi11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhoeRZ/btsHSYZFJ9p/LZD3ZeBJfk5QXvKr99Xi11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhoeRZ%2FbtsHSYZFJ9p%2FLZD3ZeBJfk5QXvKr99Xi11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;615&quot; height=&quot;256&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;매끄러운 터치 제스처 경로(왼쪽)와 합쳐진 경로(오른쪽)&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bbipzg/btsHPxOjLHg/sc1IKFKqPzsfWXyAXHi5u1/img.png&quot;&gt;&lt;/span&gt;매끄러운 터치 제스처 경로(왼쪽)와 합쳐진 경로(오른쪽)&lt;/p&gt;
&lt;pre id=&quot;code_1717847647871&quot; class=&quot;cs&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;window.addEventListener('pointermove', event =&amp;gt; {  
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대부분의 웹 애플리케이션에서는 이벤트를 합쳐서 처리해도 사용자가 만족스럽게 사용할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;드로잉 앱&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 것에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;touchmove 이벤트의 좌표를 기반&lt;/b&gt;으로 경로를 만들어야 할 때에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사이사이에 경로가 누락&lt;/b&gt;돼서 선을 매끄럽게 그리지 못할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런 경우에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;포인터 이벤트&lt;/b&gt;의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;getCoalescedEvents() 메서드&lt;/b&gt;를 사용하면 합쳐진&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트에 대한 정보를 얻을 수 있음&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ Lighthouse를 사용한다&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;브라우저에 잘 맞춰진 코드를 작성&lt;/b&gt;하고 싶은데 어디서부터 시작해야 할지 모를 때에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/overview?hl=ko&quot;&gt;&lt;b&gt;Lighthouse&lt;/b&gt;&lt;/a&gt;를 사용&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Lighthouse는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;웹 사이트의 잘 된 점과 개선할 점을 파악한 결과를 보고서&lt;/b&gt;로 보여 주는 도구&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;평가 항목에 무엇이 있는지 읽어 보는 것으로도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저가 무엇을 신경 쓰는지 알 수 있을 것&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 성능 측정 방법을 배운다&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;성능 개선 방법은 사이트마다 다르기 때문에 웹 사이트의 성능을 측정하고 가장 적합한 방식을 결정할 수 있어야 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://developer.chrome.com/docs/devtools?hl=ko&quot;&gt;&lt;b&gt;Chrome 개발자 도구 개발 팀이 작성한 튜토리얼&lt;/b&gt;&lt;/a&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;웹 사이트의 성능을 측정하는 여러 방법을 알려줌&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 사이트에 기능 정책을 추가한다&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://developer.chrome.com/blog/feature-policy?hl=ko&quot;&gt;기능&amp;nbsp;정책(Feature&amp;nbsp;policy)&lt;/a&gt;&lt;/b&gt;은 웹 플랫폼의 새로운 기능으로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;프로젝트를 구축할 때 최소한의 방어책&lt;/b&gt;이 될 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기능 정책을 사용하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;앱의 특정 동작을 보장하고 실수를 방지&lt;/b&gt;할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예를 들어 앱이 파싱을 차단하지 않도록 보장하려면 동기 스크립트 정책(synchronous scripts policy)하에 앱을 실행할 수 있고 sync-script: 'none' 값을 적용하면 파싱을 막을 수 있는 JavaScript는 실행되지 않음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이렇게 하면 코드가 파서를 차단하는 것을 방지할 수 있고, 브라우저는 파서가 멈추는 것을 걱정할 필요가 없어짐&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코드 작성과 생산성도 중요하지만 작성한 코드가 브라우저에서 어떻게 작동하는지도 생각해 보는 것이 좋음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최신 브라우저는 사용자에게 더 나은 웹 경험을 제공하기 위해 여러 방법을 개발해 왔고 앞으로도 그럴 것임&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코드를 체계화해 브라우저에서 잘 작동하게 하면 사용자에게 좋은 경험을 제공할 수 있음&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS/브라우저</category>
      <author>H.E</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/134</guid>
      <comments>https://together-cs.tistory.com/134#entry134comment</comments>
      <pubDate>Sat, 8 Jun 2024 20:54:12 +0900</pubDate>
    </item>
    <item>
      <title>브라우저 살펴보기 - 렌더러 프로세스의 내부동작(2)</title>
      <link>https://together-cs.tistory.com/133</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;기술글을 보고 정리하였음(&lt;a href=&quot;https://d2.naver.com/helloworld/5237120&quot;&gt;https://d2.naver.com/helloworld/5237120&lt;/a&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;이 글은 렌더러 프로세스가 HTML 문서를 받았을 때 어떤 절차를 거쳐 화면을 구성하는지 설명하고 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기술글이 2019년도에 작성된 글이기 때문에 현재와는 많이 다른점이 있을것이기에 이런 흐름으로 만들어졌다고 이해하고 현재와 다른점이 있다는것을 생각하면서 봐야함(크롬에 많은 버전 업데이트가 있었기 때문)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;렌더러&amp;nbsp;프로세스의&amp;nbsp;내부&amp;nbsp;동작&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;렌더러 프로세스는 여러 측면에서&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;웹 페이지의 성능에 영향&lt;/b&gt;을 끼침&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ 렌더러 프로세스는 웹 콘텐츠를 처리&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;429&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mflcv/btsHRm8UVfl/yImIXqtvApuP3qFT46j931/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mflcv/btsHRm8UVfl/yImIXqtvApuP3qFT46j931/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mflcv/btsHRm8UVfl/yImIXqtvApuP3qFT46j931/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMflcv%2FbtsHRm8UVfl%2FyImIXqtvApuP3qFT46j931%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;590&quot; height=&quot;317&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;429&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;메인 스레드와 워커 스레드, 컴포지터 스레드, 래스터 스레드가 있는 렌더러 프로세스&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/MdB3A/btsHPaFBdX0/igHzONMQSLw7XDr1VDkrU1/img.png&quot;&gt;&lt;/span&gt;메인 스레드와 워커 스레드, 컴포지터 스레드, 래스터 스레드가 있는 렌더러 프로세스&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;렌더러 프로세스&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;탭 내부에서 발생하는 모든 작업을 담당&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;렌더러 프로세스의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드&lt;/b&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저로 전송된 대부분의 코드를 처리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;간혹&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;웹 워커나 서비스 워커&lt;/b&gt;를 사용하는 경우에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;워커 스레드&lt;/b&gt;가&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;JavaScript 코드의 일부를 처리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;웹 페이지를 효율적이고 부드럽게 렌더링하기 위해&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;별도의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;(웹 페이지의 시각적 요소들을 결합하여 최종 화면에 렌더링하는 작업 담당)와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;래스터 스레드&lt;/b&gt;(웹 페이지의 각 레이어를 실제로 래스터화하는 작엄 담당, 벡터 그래픽을 픽셀 단위의 비트맵 이미지로 변화하는 과정을 처리)가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;렌더러 프로세스에서 실행됨&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;렌더러 프로세스&lt;/b&gt;의 주요 역할은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTML과 CSS, JavaScript를 사용자와 상호작용을 할 수 있는 웹 페이지로 변환&lt;/b&gt;하는 것&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ 파싱&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DOM&amp;nbsp;구축&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;페이지를 이동하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내비게이션 실행 메시지를 렌더러 프로세스가 받고 HTML 데이터를 수신&lt;/b&gt;하기 시작하면 렌더러 프로세스의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문자열(HTML)을 파싱&lt;/b&gt;해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DOM(document object model)으로 변환&lt;/b&gt;하기 시작&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DOM은 브라우저가 내부적으로 웹 페이지를 표현하는 방법일 뿐만 아니라 웹 개발자가 JavaScript를 통해 상호작용을 할 수 있는 데이터 구조이자 API&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTML 문서를 DOM으로 파싱하는 방법은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://html.spec.whatwg.org/&quot;&gt;HTML 표준&lt;/a&gt;에 정의되어 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브라우저에서 HTML 문서를 열었을 때 오류를 받지 않는데 이유는 오류를 우아하게 처리하도록 HTML 명세가 설계됐기 때문(ex. 닫는 태그 누락, 먼저 닫힌 잘못된 마크업)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하위&amp;nbsp;리소스(subresource)&amp;nbsp;로딩&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;433&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqu7cm/btsHRlvs9y6/YRUihpd4IP0E4GIo37UnUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqu7cm/btsHRlvs9y6/YRUihpd4IP0E4GIo37UnUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqu7cm/btsHRlvs9y6/YRUihpd4IP0E4GIo37UnUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdqu7cm%2FbtsHRlvs9y6%2FYRUihpd4IP0E4GIo37UnUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;552&quot; height=&quot;291&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;433&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;HTML을 파싱하고 DOM 트리를 만드는 메인 스레드&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/eeqG7p/btsHNU4ZhCT/KgrPwo60OJO2dGK2HLmKm1/img.png&quot;&gt;&lt;/span&gt;HTML을 파싱하고 DOM 트리를 만드는 메인 스레드&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;웹 사이트&lt;/b&gt;는 일반적으로 이미지, CSS, JavaScript와 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;외부 리소스를 사용&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이러한 파일은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크나 캐시에서 로딩&lt;/b&gt;해야 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DOM을 구축하기 위해 파싱하는 동안 이런 리소스를 만날 때마다 메인 스레드가 하나하나 요청할 수도 있을 것임&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;속도를 높이기&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;위해 '&lt;b&gt;프리로드(Preload) 스캐너'&lt;/b&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;동시에 실행&lt;/b&gt;됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTML 문서에 &amp;lt;img&amp;gt; 또는 &amp;lt;link&amp;gt; 와 같은 태그가 있으면 프리로드 스캐너는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTML 파서가 생성한 토큰을 확인&lt;/b&gt;하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스의 네트워크 스레드에 요청&lt;/b&gt;을 보냄&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바 스크립트가 파싱을 막을 수 있다&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;lt;script&amp;gt; 태그를 만나면 HTML 파서&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTML 문서의 파싱을 일시 중지&lt;/b&gt;한 다음&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JavaScript 코드를 로딩&lt;/b&gt;하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;파싱해 실행&lt;/b&gt;해야 함 DOM 구조 전체를 바꿀 수 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;document.write() 메서드와 같은 것을 사용해 문서의 모양을 변경할 수 있기 때문&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;HTML 파싱을 재개하기 전에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTML 파서&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JavaScript의 실행이 끝나기를 기다려야 함&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;리소스를 어떻게 로딩하길 원하는지 브라우저에 힌트를 주는 방법&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JavaScript에서 document.write() 메서드를 사용하지 않는다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&amp;lt;script&amp;gt; 태그에 async 속성이나 defer 속성&lt;/b&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;추가&lt;/b&gt;할 수 있음. 이 속성이 있으면 브라우저가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JavaScript 코드를 비동기적으로 로딩하고 실행하면서 HTML 파싱을 막지 않음&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;또한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JavaScript 모듈&lt;/b&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용&lt;/b&gt;할 수도 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;lt;link rel=&quot;preload&quot;&amp;gt;&lt;/b&gt;는 현재 내비게이션을 실행하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;리소스가 반드시 필요하다는 것을 브라우저에 알려서 리소스를 가능한 한 빨리 다운로드하려는 경우에 사용&lt;/b&gt;할 수 있음&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ 스타일 계산&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tqbNE/btsHSZYA459/CGnkGpoaKJzCDmXMckj81K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tqbNE/btsHSZYA459/CGnkGpoaKJzCDmXMckj81K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tqbNE/btsHSZYA459/CGnkGpoaKJzCDmXMckj81K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtqbNE%2FbtsHSZYA459%2FCGnkGpoaKJzCDmXMckj81K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;529&quot; height=&quot;279&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;계산된 스타일을 추가하기 위해 CSS를 파싱하는 메인 스레드&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bnmzag/btsHNTycpYU/Q8wwPEAAdECFGkPx4G1f20/img.png&quot;&gt;&lt;/span&gt;계산된 스타일을 추가하기 위해 CSS를 파싱하는 메인 스레드&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DOM만으로는 웹 페이지의 모양을 알 수 없음.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CSS&lt;/b&gt;로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;웹 페이지 요소의 모양을 결정할 수 있기 때문&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;메인 스레드&lt;/b&gt;는&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;CSS를 파싱&lt;/b&gt;하고 각&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DOM 노드에 해당되는 계산된 스타일(computed style)을 확정&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;계산된 스타일은 CSS 선택자(selector)로 구분되는 요소에 적용될 스타일에 관한 정보&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;CSS&lt;/b&gt;를&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;전혀 적용하지 않아도 DOM 노드에는 계산된 스타일이 적용&lt;/b&gt;되어 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;h1&amp;gt; 태그는 &amp;lt;h2&amp;gt; 태그보다 크게 표시되며 바깥 여백(margin)이 모든 요소에 적용됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브라우저에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기본 스타일 시트가 있기 때문&lt;/b&gt;(&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/resources/html.css&quot;&gt;html.css&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일을 보면 Chrome의 기본 CSS를 알수 있음)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ 레이아웃&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;451&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbdTeM/btsHRLmYL5K/5kU7hXg6Xlipwxd0m5J3uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbdTeM/btsHRLmYL5K/5kU7hXg6Xlipwxd0m5J3uK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbdTeM/btsHRLmYL5K/5kU7hXg6Xlipwxd0m5J3uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbdTeM%2FbtsHRLmYL5K%2F5kU7hXg6Xlipwxd0m5J3uK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;289&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;451&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;원과 사각형만을 듣는것만으로는 그림이 전체적으로 어떻게 생겼는지 알수 없음&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/uASqX/btsHNY0uwQ9/ur2vMma8oSPbk7FsrI7w0k/img.png&quot;&gt;&lt;/span&gt;원과 사각형만을 듣는것만으로는 그림이 전체적으로 어떻게 생겼는지 알수 없음&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;레이아웃은 요소의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기하학적 속성(geometry)를 찾는 과정&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;메인 스레드&lt;/b&gt;는 DOM과 계산된 스타일을 훑어가며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;레이아웃 트리를 만듬&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;레이아웃 트리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;x, y 좌표, 박스 영역(bounding box)&lt;/b&gt;의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;크기와 같은 정보&lt;/b&gt;를 가지고 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;레이아웃 트리는 DOM 트리와 비슷한 구조일 수 있지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;웹 페이지에 보이는 요소에 관련된 정보만 가지고 있음&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- display: none 속성이 적용된 요소는 레이아웃 트리에 포함되지 않음(visibility: hidden 속성이 적용된 요소는 포함)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와 비슷하게 p::before{content:&quot;Hi!} 속성과 같은 의사 클래스(pseudo class = 가상 클래스)의 콘텐츠는 DOM에는 포함되지 않지만 레이아웃 트리에는 포함&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eoIQUb/btsHR1Xw7Bp/VQ9ZSyH8zk8CsFx2yjLuv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eoIQUb/btsHR1Xw7Bp/VQ9ZSyH8zk8CsFx2yjLuv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eoIQUb/btsHR1Xw7Bp/VQ9ZSyH8zk8CsFx2yjLuv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeoIQUb%2FbtsHR1Xw7Bp%2FVQ9ZSyH8zk8CsFx2yjLuv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;278&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;계산된 스타일이 있는 DOM 트리를 돌며 레이아웃 트리를 생성하는 메인 스레드&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/wuA08/btsHOK8pUe0/GBlK9bBbiA6ufKbDqvZUfK/img.png&quot;&gt;&lt;/span&gt;계산된 스타일이 있는 DOM 트리를 돌며 레이아웃 트리를 생성하는 메인 스레드&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹 페이지의 레이아웃을 결정하는 것은 어려운 작업&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9SgW5/btsHRKuWSeD/vio8XdI7ttnNsrjjn80HG0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9SgW5/btsHRKuWSeD/vio8XdI7ttnNsrjjn80HG0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9SgW5/btsHRKuWSeD/vio8XdI7ttnNsrjjn80HG0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/9SgW5/btsHRKuWSeD/vio8XdI7ttnNsrjjn80HG0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;534&quot; height=&quot;334&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;줄 바꿈이 변해 이동하는 단락의 박스 레이아웃&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bJqN4d/btsHSzyDegf/oA0cDnp2079SVSfgBPZw81/img.gif&quot;&gt;&lt;/span&gt;줄 바꿈이 변해 이동하는 단락의 박스 레이아웃&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가장 단순하게 위에서 아래로 펼쳐지는 블록 영역 하나만 있는 웹 페이지의 레이아웃을 결정할 때에도 폰트의 크기가 얼마이고 줄 바꿈을 어디서 해야 하는지 고려해야 함(&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단락의 크기와 모양이 바뀔 수 있고, 단락의 위치에 영향이 있기 때문)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;CSS는 요소를 한쪽으로 흐르게(float) 하거나, 크기를 벗어난 부분을 보이지 않게 하거나, 글이 쓰이는 방향을 변경할 수 있음&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ 페인트&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s1uCM/btsHRZejGDU/UGrvniRVqLKjIa9Dk6Vjy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s1uCM/btsHRZejGDU/UGrvniRVqLKjIa9Dk6Vjy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s1uCM/btsHRZejGDU/UGrvniRVqLKjIa9Dk6Vjy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs1uCM%2FbtsHRZejGDU%2FUGrvniRVqLKjIa9Dk6Vjy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;233&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;어느 도형을 먼저 그려야할지 알수 없음&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/blvgNh/btsHOFGbk0j/iCMyEWCqUJrE2vk3WRHaz0/img.png&quot;&gt;&lt;/span&gt;어느 도형을 먼저 그려야할지 알수 없음&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DOM, 스타일, 레이아웃을 가지고도 여전히 페이지를 렌더링할 수 없음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;요소의 크기, 모양, 위치를 알더라도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;어떤 순서로 그려야 할지 판단&lt;/b&gt;해야 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;z-index 속성이 적용되었다면 HTML에 작성된 순서로 요소를 그리면 잘못 렌더링된 화면이 나옴&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉,&amp;nbsp;&lt;b&gt;DOM에 선언된 노드 순서와 페인트 순서는 많이 다를 수 있음&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lnb0q/btsHSzlENuU/3vl1b2Yoeq9Wp3XVkKMVPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lnb0q/btsHSzlENuU/3vl1b2Yoeq9Wp3XVkKMVPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lnb0q/btsHSzlENuU/3vl1b2Yoeq9Wp3XVkKMVPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flnb0q%2FbtsHSzlENuU%2F3vl1b2Yoeq9Wp3XVkKMVPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;545&quot; height=&quot;295&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;레이아웃 트리를 순회하며 페인트 기록을 생성하는 메인 스레드&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/ccSbeG/btsHNynxbPA/szWN9Owx7zusc7WkNtTtAk/img.png&quot;&gt;&lt;/span&gt;레이아웃 트리를 순회하며 페인트 기록을 생성하는 메인 스레드&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;페인트 단계에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;페인트 기록(paint record)을 생성&lt;/b&gt;하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;레이아웃 트리를 순회&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;페인트 기록&lt;/b&gt;은 '배경 먼저, 다음은 텍스트, 그리고 직사각형'과 같이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;페인팅 과정을 기록한 것&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;렌더링 파이프라인을 갱신하는 데는 많은 비용이 든다&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DTxJW/btsHR4NoTcs/FLP2Zh5lCPjpaptcC5k6X1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DTxJW/btsHR4NoTcs/FLP2Zh5lCPjpaptcC5k6X1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DTxJW/btsHR4NoTcs/FLP2Zh5lCPjpaptcC5k6X1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/DTxJW/btsHR4NoTcs/FLP2Zh5lCPjpaptcC5k6X1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;510&quot; height=&quot;319&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;DOM 트리 및 스타일, 레이아웃 트리, 페인트 트리의 순서로 생성&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/xLE9k/btsHPayUG6W/XrK5qM3CkwKCxykgjsw1Y0/img.gif&quot;&gt;&lt;/span&gt;DOM 트리 및 스타일, 레이아웃 트리, 페인트 트리의 순서로 생성&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;렌더링 파이프라인&lt;/b&gt;에서 파악해야 할 가장 중요한 점은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;각 단계에서 이전 작업의 결과가 새 데이터를 만드는 데 사용&lt;/b&gt;되는 것&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예를 들어 레이아웃 트리에서 변경이 생겨 문서의 일부가 영향을 받으면 페인팅 순서도 새로 생성해야 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FxqtE/btsHRo6Ipea/j4KWtMEibtKZyoVQ0Cy230/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FxqtE/btsHRo6Ipea/j4KWtMEibtKZyoVQ0Cy230/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FxqtE/btsHRo6Ipea/j4KWtMEibtKZyoVQ0Cy230/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFxqtE%2FbtsHRo6Ipea%2Fj4KWtMEibtKZyoVQ0Cy230%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;612&quot; height=&quot;144&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;애니메이션 타임라인에서 애니메이션 프레임과 JavaScript 때문에 렌더링이 막힌 프레임&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/ctzbIe/btsHOCQndvz/pABW4MYiEwXDHk9GUGToEk/img.png&quot;&gt;&lt;/span&gt;애니메이션 타임라인에서 애니메이션 프레임과 JavaScript 때문에 렌더링이 막힌 프레임&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;요소에 애니메이션을 적용하면 브라우저는 모든 프레임 사이에서 이러한 작업을 해야 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대부분의 디스플레이 장치는 화면을 초당 60번 새로 고침(60fps)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;요소의 움직임이 모든 프레임에 반영되어야 사람이 볼 때 부드럽게 느껴짐&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;애니메이션에서 프레임이 누락되면 웹 페이지가 '버벅대는(janky)' 것처럼 보임&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0HulM/btsHTjvCzIq/rKqWN76ekARvkFwbLPkGt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0HulM/btsHTjvCzIq/rKqWN76ekARvkFwbLPkGt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0HulM/btsHTjvCzIq/rKqWN76ekARvkFwbLPkGt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0HulM%2FbtsHTjvCzIq%2FrKqWN76ekARvkFwbLPkGt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;675&quot; height=&quot;142&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;애니메이션 타임라인에서 애니메이션 프레임과 JavaScript 때문에 렌더링이 막힌 프레임&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bFgnF8/btsHOCv2HV4/bLO5wDrkk5lXdf1K4glluK/img.png&quot;&gt;&lt;/span&gt;애니메이션 타임라인에서 애니메이션 프레임과 JavaScript 때문에 렌더링이 막힌 프레임&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;화면 주사율에 맞추어 렌더링 작업이 이루어져도 이 작업은 메인 스레드에서 실행되기 때문에 애플리케이션이 JavaScript를 실행하는 동안 렌더링이 막힐 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbf7cx/btsHSALCCI1/HkHVxLWHskJ9MKR0e18TXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbf7cx/btsHSALCCI1/HkHVxLWHskJ9MKR0e18TXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbf7cx/btsHSALCCI1/HkHVxLWHskJ9MKR0e18TXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbf7cx%2FbtsHSALCCI1%2FHkHVxLWHskJ9MKR0e18TXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;590&quot; height=&quot;127&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;애니메이션 프레임에 맞춰 애니메이션 타임라인에서 실행되는 더 작은 JavaScript 덩어리&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bJY3pV/btsHNb0HGFv/F2rWTj6qKCPHObJSkWouEK/img.png&quot;&gt;&lt;/span&gt;애니메이션 프레임에 맞춰 애니메이션 타임라인에서 실행되는 더 작은 JavaScript 덩어리&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JavaScript 작업을 작은 덩어리로 나누고 requestAnimationFrame() 메서드를 사용해 프레임마다 실행하도록 스케줄을 관리할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Reflow와 Repaint 최소화하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;브라우저 렌더링 최적화하기&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;렌더링이 반복되는 경우&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #171717; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바스크립트에 의한 노드 추가 또는 삭제&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브라우저 창의 리사이징에 의한 뷰포트 크기 변경&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTML 요소의 레이아웃에 변경을 발생시키는 스타일 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;Layout 계산과 Paint 과정이 재차 실행&lt;/b&gt;되어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;리렌더링&lt;/b&gt;이 발생&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;b&gt;Layout 계산을 다시 수행&lt;/b&gt;하는 것을&amp;nbsp;&lt;/span&gt;&lt;b&gt;Reflow&lt;/b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;, 픽셀을 렌더링하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Paint 작업을 다시 하는 것&lt;/b&gt;을&amp;nbsp;&lt;/span&gt;&lt;b&gt;Repaint&lt;/b&gt;라고 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 주의해야할 점은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Reflow가 발생하면 Repaint까지 발생하게 되므로 큰 비용이 발생한다는 점&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 발생시킨다면 paint부터 시작될 수 있도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Repaint만 발생&lt;/b&gt;하게 되는것이 훨씬&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;비용적 이점&lt;/b&gt;이 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Reflow와 Repaint 최소화&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;영향받는 노드 최소화하기 (position fixed, absolute)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;상위 노드의 스타일을 변경하면 하위 노드에 모두 영향을 주게 됨&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;따라서 다른 엘리먼트 레이아웃에 영향을 주지 않는 fixed와 absolute 속성을 사용하면 비용을 줄일 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;숨겨진 엘리먼트 수정&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;display: none의 경우 Reflow와 Repaint가 발생하지 않음&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;많은 수의 엘리먼트를 변경해야 할 경우, 숨겨진 상태에서 변경하고 다시 보이도록 display: none 속성을 설정하여 레이아웃 발생을 최대한 줄일 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주의: visibility: hidden의 경우 보이지 않고 존재는 하기 때문에 layout 발생&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;transform, opacity 속성 사용&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두 속성은 reflow와 repaint가 일어나지 않는 속성&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;left, right 대신 transform 속성을 사용&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;visibility, display 대신 opacity 속성을 사용하면 reflow, repaint 발생을 최소화 할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;애니메이션 최적화&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;한 프레임의 처리는 16ms(60fps) 내로 완료되어야 끊기는 현상 없이 자연스럽게 처리&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바스크립트에서 setTimeout을 이용하여 애니메이션을 구현한다면 이벤트 루프에 의해 딜레이가 생길 수 있고, 16ms 안에 실행하지 못 한다면 해당 프레임은 유실됨&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 도와주는 것이 requestAnimationFrame() 메서드(리페인트 바로 전에 브라우저가 애니메이션을 업데이트 할 지정된 함수를 호출하도록 요청함 즉, 리페인트 이전에 호출할 인수로 콜백을 받)&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;장점: 지연 및 블로킹 없이 일정한 간격으로 애니메이션을 수행할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브라우저 프레임 속도(60fps)에 맞춰 애니메이션을 실행할 수 있도록 함&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;페이지가 비활성 상태일 때 렌더링을 중지(CPU의 리소스와 배터리 수명을 낭비하지 않아도 됨)&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와 달리 setTimeout은 백그라운드 상태일 때도 계속 실행됨&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ 합성&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;페이지는 어떻게 그려질까&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yjg8V/btsHSzlENv5/19ZE1h7Nls8EMG5nu0IbS0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yjg8V/btsHSzlENv5/19ZE1h7Nls8EMG5nu0IbS0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yjg8V/btsHSzlENv5/19ZE1h7Nls8EMG5nu0IbS0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/Yjg8V/btsHSzlENv5/19ZE1h7Nls8EMG5nu0IbS0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;411&quot; height=&quot;257&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;가장 단순한 래스터화 과정&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/q2bUt/btsHOYeHJ9j/wYZYRYiiF6O4Qt5lhsKefK/img.gif&quot;&gt;&lt;/span&gt;가장 단순한 래스터화 과정&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;정보&lt;/b&gt;(&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;브라우저는 문서의 구조와 각 요소의 스타일, 요소의 기하학적 속성, 페인트 순서&lt;/span&gt;)를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;화면의 픽셀로 변환&lt;/b&gt;하는 작업을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;래스터화(rasterizing)&lt;/b&gt;라고 함&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;가장 단순한 래스터화&lt;/b&gt;는 아마&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;뷰포트 안쪽을 래스터&lt;/b&gt;하는 것일 것&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자가 웹 페이지를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;스크롤&lt;/b&gt;하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이미 래스터화한 프레임을 움직이고 나머지 빈 부분을 추가로 래스터화&lt;/b&gt;함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 방식은 Chrome이 처음 출시되었을 때 래스터화한 방식이지만 현재는&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;브라우저는 합성(compositing)&lt;/b&gt;이라는 보다 정교한 과정을 거침(렌더링 파이프라인에서는 이단계부터 GPU가 많이 사용됨)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;합성이란&amp;nbsp;무엇인가&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8J7VB/btsHSt0cC4P/agkjbxVf0AOZOHRz6SydL1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8J7VB/btsHSt0cC4P/agkjbxVf0AOZOHRz6SydL1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8J7VB/btsHSt0cC4P/agkjbxVf0AOZOHRz6SydL1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/b8J7VB/btsHSt0cC4P/agkjbxVf0AOZOHRz6SydL1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;470&quot; height=&quot;294&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;합성과정&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/4TXot/btsHO1oLzoZ/YuKNllL3AeyBsrnGI9hK31/img.gif&quot;&gt;&lt;/span&gt;합성과정&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;합성&lt;/b&gt;은 웹 페이지의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;각 부분을 레이어로 분리해 별도로 래스터화&lt;/b&gt;하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터 스레드(compositor thread)&lt;/b&gt;라고 하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;별도의 스레드&lt;/b&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;웹 페이지로 합성&lt;/b&gt;하는 기술&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스크롤되었을 때 레이어는 이미 래스터화되어 있으므로 새 프레임을 합성하기만 하면 됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;애니메이션&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;역시 레이어를 움직이고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;합성하는 방식&lt;/b&gt;으로 만들 수 있음&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여러 레이어로 나누기&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;455&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K96w6/btsHSA5XvRw/k3rwlLUsqPZvwRB4dqJr2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K96w6/btsHSA5XvRw/k3rwlLUsqPZvwRB4dqJr2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K96w6/btsHSA5XvRw/k3rwlLUsqPZvwRB4dqJr2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK96w6%2FbtsHSA5XvRw%2Fk3rwlLUsqPZvwRB4dqJr2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;476&quot; height=&quot;250&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;455&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;레이어 트리를 만들면서 레이아웃 트리를 순회하는 메인 스레드&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/eCAOfI/btsHNXHC5LG/PKh8gdPzx54F14p1DVlk30/img.png&quot;&gt;&lt;/span&gt;레이어 트리를 만들면서 레이아웃 트리를 순회하는 메인 스레드&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어떤 요소가 어떤 레이어에 있어야 하는지 확인하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;레이아웃 트리를 순회&lt;/b&gt;하며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;레이어 트리&lt;/b&gt;를 만듬&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;뷰포트로 미끄러져 들어오는 들어오는 슬라이드인 메뉴처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;별도의 레이어&lt;/b&gt;여야 하는 웹 페이지의 어떤 부분이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;별도의 레이어가 아니라면&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;CSS의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;will-change 속성&lt;/b&gt;을 사용해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저가 레이어를 생성하게 힌트&lt;/b&gt;를 줄 수 있음&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모든 요소에 레이어를 할당하면 좋을 것 같지만 수많은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;레이어를 합성하는 작업&lt;/b&gt;은 웹 페이지의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;작은 부분을 매 프레임마다 새로 래스터화하는 작업보다 더 오래 걸릴 수 있음&lt;/b&gt;(확인하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;애플리케이션의 렌더링 성능은 직접 측정해 봐야 함)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;레이어가 많으면 합성 비용이 높을 뿐만 아니라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;레이어를 메모리에 가지고 있어야 하는 부담&lt;/b&gt;도 있음(&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Chrome은 레이어가 과도하게 많아지는 것(layer explosion)을 막기 위해 특정한 경우에는 레이어를 생성하지 않거나 합치기도 함)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메인 스레드 이후 래스터화와 합성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;455&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcWPjZ/btsHS6iYdQT/jP4bbm83UepSZpehk9FXaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcWPjZ/btsHS6iYdQT/jP4bbm83UepSZpehk9FXaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcWPjZ/btsHS6iYdQT/jP4bbm83UepSZpehk9FXaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcWPjZ%2FbtsHS6iYdQT%2FjP4bbm83UepSZpehk9FXaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;262&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;455&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-alt=&quot;타일 단위로 비트맵을 만들고 GPU로 보내는 래스터 스레드&quot; data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/sMXIV/btsHOHEhANU/xhkWG6scHzOg7jlYUycx4k/img.png&quot;&gt;&lt;/span&gt;타일 단위로 비트맵을 만들고 GPU로 보내는 래스터 스레드&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;레이어 트리가 생성&lt;/b&gt;되고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;페인트 순서가 결정&lt;/b&gt;되면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드가 해당 정보를 컴포지터 스레드에 넘김(commit)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;는 각&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;레이어를 래스터화&lt;/b&gt;함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어떤 레이어는 페이지의 전체 길이만큼 클 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;레이어를 타일(tile) 형태로 나눠 각 타일을 래스터 스레드로 보냄&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;래스터 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;각 타일을 래스터화해 GPU 메모리에 저장&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;래스터 스레드간의 우선순위를 지정&lt;/b&gt;할 수 있어서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;뷰포트 안이나 근처의 것들이 먼저 래스터화&lt;/b&gt;될 수&amp;nbsp; 있음 또한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;레이어는 줌인&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 동작을 처리하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;여러 해상도별로 타일 세트를 여러 벌&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가지고 있음(&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;타일 세트의 모든 타일이 래스터화되어 있지는 않기 때문에 최대한 구멍을 메울 수 있는 방식으로 여러 타일 세트의 타일을 조합해서 사용. 래스터화하지 못한 영역은 체스판의 하얀색 부분처럼 빈곳으로 둠 &amp;rarr; 이 단계의 큰 목표는 이 하얀 빈곳을 줄이는 것&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;타일이&amp;nbsp;래스터화&lt;/b&gt;되면&amp;nbsp;&lt;b&gt;컴포지터&amp;nbsp;스레드&lt;/b&gt;는&lt;b&gt;&amp;nbsp;'합성&amp;nbsp;프레임'&lt;/b&gt;을 생성하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;타일의 정보를 모음&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 타일의 정보를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'드로 쿼드(draw quads)'&lt;/b&gt;라고 부름&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;드로 쿼드: 메모리 타일의 위치와 웹 페이지 합성을 고려해 타일을 웹 페이지의 어디에 그려야 하는지에 관한 정보를 가지고 있음&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;합성 프레임: 웹 페이지의 프레임을 나타내는 드로 쿼드의 모음&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이후에&amp;nbsp;&lt;b&gt;합성&amp;nbsp;프레임&lt;/b&gt;이&amp;nbsp;&lt;b&gt;IPC를 통해 브라우저 프로세스로 전송&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 시점에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 UI의 변경을 반영&lt;/b&gt;하려는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UI 스레드나 확장 앱&lt;/b&gt;을 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다른 렌더러 프로세스&lt;/b&gt;에 의해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;합성 프레임이 더 추가&lt;/b&gt;될 수 있음 이러한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;합성 프레임은 GPU로 전송되어 화면에 표시&lt;/b&gt;됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;스크롤 이벤트가 발생&lt;/b&gt;하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;GPU로 보낼 다른 합성 프레임을 만듬&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기술글(2019년 작성)에서는 '&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;합성 프레임이 브라우저 프로세스를 거치지 않고 GPU 프로세스로 바로 보내지는 형태로 변경될 예정'이라고 되어있었는데 검색으로 해보니 현재 크롬의 합성 아키텍처는 성능과 효율성을 개선하기 위해 많은 변화가 있었다고 함 주요 목표는 중간 단계를 거치지 않고 직접 GPU 프로세스로 합성하는 것 따라서 현재는 합성 단계가 많이 다를꺼라고 생각함 찾아보니&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://velog.io/@adultlee/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EA%B0%80-%EA%B7%B8%EB%A6%AC%EB%8A%94-%EB%B2%95&quot;&gt;이 2023년 작성된 블로그글&lt;/a&gt;을 확인해보니 '프로세스를 가속화하기 위해 래스터 스레드는 IPC를 통해 타일을 GPU 프로세스로 보낸다'고 되어있음 좀더 현재에 가까운 동작방법을 알기 위해서 이 글을 참조하며 이해하는것이 훨씬 좋아 보임&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;합성의 이점&lt;/b&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드와 별개로 작동&lt;/b&gt;할 수 있다는 점&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;컴포지터 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JavaScript 실행이나 스타일 계산을 기다리지 않아도 됨&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이것이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;합성만 하는 애니메이션이 성능상 가장 부드럽다&lt;/b&gt;고 보는 이유&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;레이아웃이나 페인트를 다시 계산&lt;/b&gt;해야 할 경우에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메인 스레드가 관여&lt;/b&gt;해야 함&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS/브라우저</category>
      <author>H.E</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/133</guid>
      <comments>https://together-cs.tistory.com/133#entry133comment</comments>
      <pubDate>Sat, 8 Jun 2024 20:53:26 +0900</pubDate>
    </item>
    <item>
      <title>브라우저 살펴보기 - 내비게이션 과정에서 일어나는 일(1)</title>
      <link>https://together-cs.tistory.com/132</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;기술글을 보고 정리하였음(&lt;a href=&quot;https://d2.naver.com/helloworld/2922312&quot;&gt;https://d2.naver.com/helloworld/2922312&lt;/a&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;저번에 이어 웹 사이트를 표시하기 위해 각 프로세스와 스레드가 어떻게 통신하는지 좀 더 깊게 알아보고 있음&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기술글이 2019년도에 작성된 글이기 때문에 현재에는 사용되지 않는 이벤트등이 기재되어있어 이런 흐름으로 페이지 이동을 한다고 생각하면 될듯 (크롬에 많은 버전 업데이트가 있었기 때문)&lt;br /&gt;&lt;br /&gt;내용을 알기 전에 브라우저 동작과정과 프로세스와 쓰레드에 대한 기본 지식을 가지고 읽어야 이해하기 좋음&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;color: #555555; text-align: start;&quot;&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;내비게이션&amp;nbsp;과정에서&amp;nbsp;일어나는&amp;nbsp;일&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브라우저의 주소 표시줄에 URL을 입력하면 브라우저가 인터넷에서 데이터를 가져와서 페이지를 표시함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 동작에서 사용자가 사이트를 요청하고 브라우저가 페이지 렌더링을 준비하는 과정(= 내비게이션 = 사이트간의 이동)에 초점을 맞춰 살펴볼것임&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 브라우저 프로세스에서 시작&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6rbfi/btsHSqCuxYf/ibk8DGyUqtuAzbSfigB9C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6rbfi/btsHSqCuxYf/ibk8DGyUqtuAzbSfigB9C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6rbfi/btsHSqCuxYf/ibk8DGyUqtuAzbSfigB9C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6rbfi%2FbtsHSqCuxYf%2Fibk8DGyUqtuAzbSfigB9C0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;438&quot; height=&quot;251&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
브라우저 UI와 브라우저 프로세스(UI 스레드와 네트워크 스레드, 스토리지 스레드 )
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;브라우저 프로세스&lt;/b&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;탭 영역 밖에 있는 모든 부분을 제어&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브라우저 프로세스에는 UI 스레드와 네트워크 스레드, 스토리지 스레드 등이 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;UI 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저의 버튼과 입력란을 그림&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;네트워크 스레드&lt;/b&gt;는 인터넷에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터를 가져오기 위해 네트워크 스택&lt;/b&gt;을 다룸&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;스토리지 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;파일에 대한 접근을 제어&lt;/b&gt;함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주소 표시줄에 URL을 입력하면 브라우저 프로세스의 UI 스레드가 입력을 처리&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 간단한 내비게이션&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1단계:&amp;nbsp;입력&amp;nbsp;처리&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;817&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5psXb/btsHS82avLR/yHoSfKcqbameAcytSQnYp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5psXb/btsHS82avLR/yHoSfKcqbameAcytSQnYp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5psXb/btsHS82avLR/yHoSfKcqbameAcytSQnYp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5psXb%2FbtsHS82avLR%2FyHoSfKcqbameAcytSQnYp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;461&quot; height=&quot;270&quot; data-origin-width=&quot;817&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
입력되는 내용이 검색어인지 URL인지 확인하는 UI 스레드
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;주소 표시줄에 타이핑&lt;/b&gt;을 시작하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UI 스레드&lt;/b&gt;는 먼저&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;입력되는 내용이 검색어(search query)인지 URL인지&amp;nbsp;확인&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Chrome에서 주소 표시줄은 검색창이기도 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;UI 스레드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;입력되는 내용을 파싱&lt;/b&gt;해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;검색 엔진으로 이동할지 요청한 사이트로 이동할지 결정&lt;/b&gt;해야&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 사용자가 입력한 문자열이 '검색어'라면 문자열을 사용자가 선택한 검색 엔진의 URL과 조합해 새로운 URL 형태로 변환함. 이런 변환을 위해 Chrome은 검색 엔진의 URL 주소를 관리&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;입력된 문자열이 검색어인지 URL인지 판별하는 것은 어려운 일이기 때문에 브라우저는 이를 도와줄 서버와 통신하거나 DNS Lookup(도메인 네임 시스템 조회)을 실행하기도 함 네이버에서 개발한 브라우저인 Whale의 '사이트 곧장 가기' 기능도 이 단계에서 실행되는 기능&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2단계: 내비게이션 시작&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj7xMD/btsHR8hPDEP/CsVIVXPi0LMxoPKubyVxY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj7xMD/btsHR8hPDEP/CsVIVXPi0LMxoPKubyVxY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj7xMD/btsHR8hPDEP/CsVIVXPi0LMxoPKubyVxY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj7xMD%2FbtsHR8hPDEP%2FCsVIVXPi0LMxoPKubyVxY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;556&quot; height=&quot;320&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
mysite.com 으로 이동하기 위해 네트워크 스레드와 통신하는 UI 스레드
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;사용자가 Enter 키&lt;/b&gt;를 누르면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사이트의 콘텐츠를 가져오기&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UI 스레드&lt;/b&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 호출&lt;/b&gt;을 시작&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로딩 스피너가 탭의 모서리에 표시되고, 네트워크 스레드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;요청에 대한 DNS Lookup 및 TLS 연결 설정과 같은 적절한 프로토콜을 거쳐 요청을 처리&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이때 네트워크 스레드가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTTP 301과 같은 서버 리디렉션 헤더를 수신&lt;/b&gt;할 수도 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런 경우에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 스레드가 UI 스레드와 통신해 서버가 리디렉션을 요청했다는 것을 알림&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그런 다음&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;새로운 URL 요청이 시작&lt;/b&gt;됨&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3단계:&amp;nbsp;응답&amp;nbsp;읽기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k51wY/btsHTEGq5Cy/zXFe8CdtEQoHfPwc4yVcxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k51wY/btsHTEGq5Cy/zXFe8CdtEQoHfPwc4yVcxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k51wY/btsHTEGq5Cy/zXFe8CdtEQoHfPwc4yVcxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk51wY%2FbtsHTEGq5Cy%2FzXFe8CdtEQoHfPwc4yVcxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;436&quot; height=&quot;210&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Content-Type을 포함하는 응답 헤더와 실제 데이터인 페이로드
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;응답 본문인 페이로드가 들어오기 시작&lt;/b&gt;하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;필요에 따라 스트림의 처음 몇 바이트를 확인&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;페이로드가 어떤 형식의 데이터인지&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;응답 헤더의 Content-Type 헤더&lt;/b&gt;가 알려 주지만 정보가 없거나 잘못된 정보가 있을 수 있음 그래서 이때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;MIME 스니핑&lt;/b&gt;(리소스를 보고 올바른 MIME 타입(파일 형식)을 추측)을&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;실행해 데이터의 실제 형식을 알아냄&lt;/b&gt;(매우 까다로운 작업이기에 브라우저가 다양한 방법으로 Content-Type 헤더와 페이로드를 처리)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;473&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zSXUC/btsHRJW6I1s/eKtcRBZVuGy9r5xmN2ZMTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zSXUC/btsHRJW6I1s/eKtcRBZVuGy9r5xmN2ZMTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zSXUC/btsHRJW6I1s/eKtcRBZVuGy9r5xmN2ZMTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzSXUC%2FbtsHRJW6I1s%2FeKtcRBZVuGy9r5xmN2ZMTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;486&quot; height=&quot;279&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;473&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
응답 데이터가 안전한 사이트의 HTML 문서인지 확인하는 네트워크 스레드
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;응답이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTML 파일&lt;/b&gt;이라면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터를 렌더러 프로세스에 전달&lt;/b&gt;하는 단계로 넘어감&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만 응답이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ZIP 형식 파일&lt;/b&gt;이나 다른 형식의 파일이라면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다운로드 요청이므로 다운로드 매니저에 데이터를 전달&lt;/b&gt;하는 단계로 넘어가야 함(렌더러 프로세스가 다룰 수 있는 데이터 형식일때와 렌더러 프로세스가 다룰 수 없는 데이터 형식일때로 구분 - ex. PDF파일을 반환하는 주소로 접근했을 때 다운로드가 아닌 브라우저에서 문서를 바로 표시)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 단계는 또한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Safe Browsing의 검사가 실행&lt;/b&gt;되는 단계&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;도메인과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;응답 데이터가 악성 사이트로 알려진 사이트와 일치&lt;/b&gt;하는 것 같다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 스레드는 경고 페이지를 표시&lt;/b&gt;하라고 알림&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이에 더해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CORB(Cross-Origin Read Blocking)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기능이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서로 다른 사이트&lt;/b&gt;(cross-site)의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;민감한 데이터가 렌더러 프로세스에서 실행되지 않게 검사&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3단계: 렌더러 프로세스 찾기&lt;/b&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;829&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRbZDd/btsHRMzp5Rp/7IK3KJ3TjHW7uz8gmtHiU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRbZDd/btsHRMzp5Rp/7IK3KJ3TjHW7uz8gmtHiU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRbZDd/btsHRMzp5Rp/7IK3KJ3TjHW7uz8gmtHiU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRbZDd%2FbtsHRMzp5Rp%2F7IK3KJ3TjHW7uz8gmtHiU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;287&quot; data-origin-width=&quot;829&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
UI 스레드에게 렌더러 프로세스를 찾으라고 알리는 네트워크 스레드
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모든 검사가 끝나고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저가 요청된 사이트로 이동&lt;/b&gt;해야 한다고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 스레드가 확신&lt;/b&gt;하게 되면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 스레드는 UI 스레드에 데이터가 준비되었음을 알림&lt;/b&gt;. 그러면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UI 스레드는 웹 페이지의 렌더링을 수행할 렌더러 프로세스를 찾음&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;네트워크 요청이 응답을 받기까지 수백 밀리초가 걸릴 수 있기 때문에 이 과정을 더 빨리 진행하기 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;최적화가 적용&lt;/b&gt;되어 있음. 2단계에서 UI 스레드가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 스레드로 URL 요청을 보낼 때 UI 스레드는 어느 사이트로 이동할지 알고 있음&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;UI 스레드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;렌더러 프로세스를 먼저 찾거나 네트워크 요청과 동시에 렌더러 프로세스를 시작&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런 방식에서는 모든 것이 예상대로 잘 진행된다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 스레드가 데이터를 받을 때 이미 렌더러 프로세스는 준비 상태&lt;/b&gt;에 있게 됨. 만약 다른 사이트로 리디렉션이 이루어져&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다른 프로세스가 필요하게 되면 미리 준비한 프로세스가 사용되지 않을 수도 있음&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4 단계: 내비게이션 실행&lt;/b&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cumHRm/btsHS73gydN/oGUTznGZxtsPP4szksT0z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cumHRm/btsHS73gydN/oGUTznGZxtsPP4szksT0z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cumHRm/btsHS73gydN/oGUTznGZxtsPP4szksT0z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcumHRm%2FbtsHS73gydN%2FoGUTznGZxtsPP4szksT0z1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;267&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
브라우저 프로세스와 렌더러 프로세스 간의 IPC 통신. 페이지 렌더링을 요청
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터와 렌더러 프로세스가 준비되었으므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내비게이션을 실행&lt;/b&gt;하도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스&lt;/b&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;렌더러 프로세스로 IPC 메시지를 전송&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;또한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;렌더러 프로세스가 HTML 데이터를 계속 수신&lt;/b&gt;할 수 있도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스는 데이터 스트림&lt;/b&gt;(데이터가&amp;nbsp;지속적으로&amp;nbsp;흐르는&amp;nbsp;방식으로&amp;nbsp;전달되는&amp;nbsp;것을&amp;nbsp;의미)을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;전달&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;렌더러 프로세스&lt;/b&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내비게이션이 실행&lt;/b&gt;되었다는 것을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스가 확인&lt;/b&gt;하고 나면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내비게이션이 완료&lt;/b&gt;되고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문서 로딩 단계가 시작&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 로딩은 프로그램&amp;nbsp;동작에&amp;nbsp;필요한&amp;nbsp;프로그램&amp;nbsp;그&amp;nbsp;자체와&amp;nbsp;리소스를&amp;nbsp;보조&amp;nbsp;기억장치(가령&amp;nbsp;하드디스크)에서&amp;nbsp;주기억장치(메모리)로&amp;nbsp;불러들이는&amp;nbsp;과정&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이&amp;nbsp;시점에&amp;nbsp;&lt;b&gt;주소&amp;nbsp;표시줄이&amp;nbsp;업데이트&lt;/b&gt;되고&amp;nbsp;&lt;b&gt;보안&amp;nbsp;표시&lt;/b&gt;와&amp;nbsp;&lt;b&gt;사이트 설정 UI도 새 페이지의 사이트 정보를 반영해 갱신&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;탭에&amp;nbsp;대한&amp;nbsp;세션&amp;nbsp;기록이&amp;nbsp;업데이트&lt;/b&gt;되어 뒤로 가기 버튼과 앞으로 가기 버튼도 방금 이동한 사이트를 반영해 작동&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;탭이나 창을 닫은 이후 탭과 세션을 복원&lt;/b&gt;할 수 있게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;세션 기록이 디스크 드라이브에 저장&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;추가 단계: 초기 로드 완료&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mNtbi/btsHS9fHgkM/vi0neZoDHUB6bqS7FwY7v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mNtbi/btsHS9fHgkM/vi0neZoDHUB6bqS7FwY7v0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mNtbi/btsHS9fHgkM/vi0neZoDHUB6bqS7FwY7v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmNtbi%2FbtsHS9fHgkM%2Fvi0neZoDHUB6bqS7FwY7v0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;539&quot; height=&quot;294&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;469&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
렌더러 프로세스가 브라우저 프로세스에 페이지가 '로딩되었다'는 것을 알리기 위한 IPC 통신
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;내비게이션이 실행&lt;/b&gt;되면 렌더러&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;프로세스는 계속 리소스를 로딩하고 페이지를 렌더링&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;렌더러 프로세스&lt;/b&gt;가&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;렌더링을 '끝내면'&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스로 IPC 메시지를 보냄&lt;/b&gt;(이 시점은 페이지의 모든 프레임에서 onload 이벤트(문서의 모든 콘텐츠가 로드된 후 발생하는 이벤트)의 실행까지 끝낸 이후)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UI 스레드&lt;/b&gt;는 탭에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;로딩 스피너의 작동을 중지&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;'끝낸다(finish)'라고 표현한 이유는 클라이언트 사이드의 JavaScript가 여전히 추가적인 리소스를 로드하거나 이후에 새로운 뷰를 렌더링할 수도 있기 때문&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 다른 사이트로 내비게이션&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;863&quot; data-origin-height=&quot;473&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JTsp9/btsHRanfLXH/0zK2pIYFgieiqj1IpWwPl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JTsp9/btsHRanfLXH/0zK2pIYFgieiqj1IpWwPl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JTsp9/btsHRanfLXH/0zK2pIYFgieiqj1IpWwPl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJTsp9%2FbtsHRanfLXH%2F0zK2pIYFgieiqj1IpWwPl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;539&quot; height=&quot;295&quot; data-origin-width=&quot;863&quot; data-origin-height=&quot;473&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
브라우저 프로세스가 렌더러 프로세스에 다른 사이트로 이동한다는 것을 알려주는 IPC 통신
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자가 주소 표시줄에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다른 URL을 다시 입력&lt;/b&gt;하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스는 동일한 단계를 거쳐 다른 사이트로 이동을 처리&lt;/b&gt;함. 하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;그전에 현재 렌더링된 사이트에서 beforeunload 이벤트&lt;/b&gt;(리소스가 언로드 되려고 할때 시작)를&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;확인&lt;/b&gt;해야 함&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;beforeunload(꼭 필요한 경우 사용. 이벤트 핸들러를 실행해야하기 때문에 대기 시간이 늘어남) 이벤트는 탭을 닫거나 이동하려고 할 때 &quot;이 사이트를 떠나시겠습니까?&quot;라는 경고창을 만들 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JavaScript 코드를 포함해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;탭 안의 모든 것은 렌더러 프로세스에 의해 처리&lt;/b&gt;되므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;새로운 내비게이션 요청이 들어오면 현재 렌더러 프로세스를 확인&lt;/b&gt;해야 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1Cw0X/btsHRHStAqh/ffXavKTa90KSKrA4ePx3G1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1Cw0X/btsHRHStAqh/ffXavKTa90KSKrA4ePx3G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1Cw0X/btsHRHStAqh/ffXavKTa90KSKrA4ePx3G1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1Cw0X%2FbtsHRHStAqh%2FffXavKTa90KSKrA4ePx3G1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;578&quot; height=&quot;314&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
브라우저 프로세스가 새로운 렌더러에는 프로세스에게 페이지를 렌더링하라고 알리는 IPC 통신과 브라우저 프로레스가 이전 렌더러 프로세스에 웹 페이지를 떠나라고 알리는 IPC 통신
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자가&amp;nbsp;링크를&amp;nbsp;클릭하거나&amp;nbsp;클라이언트&amp;nbsp;사이드&amp;nbsp;JavaScript에서&amp;nbsp;window.location&amp;nbsp;=&amp;nbsp;&quot;&lt;a href=&quot;https://newsite.com&quot;&gt;https://newsite.com&lt;/a&gt;&quot;&amp;nbsp;코드를&amp;nbsp;실행하는&amp;nbsp;것과&amp;nbsp;같이&amp;nbsp;&lt;b&gt;렌더러&amp;nbsp;프로세스에서&amp;nbsp;내비게이션이&amp;nbsp;시작&lt;/b&gt;되면&amp;nbsp;&lt;b&gt;렌더러 프로세스는 먼저 beforeunload 이벤트 핸들러를 확인&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;이후에는 브라우저 프로세스가 내비게이션을 시작했을 때와 동일한 과정&lt;/b&gt;을 거침&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;유일한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;차이점&lt;/b&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내비게이션 요청이 렌더러 프로세스에서 시작&lt;/b&gt;되어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 프로세스로 넘어간다는 점&lt;/b&gt;이다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;현재 렌더링된 사이트와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다른 사이트로 이동하는 새로운 내비게이션이 발생&lt;/b&gt;하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;별도의 렌더러 프로세스가 새로운 내비게이션을 처리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;현재 렌더링된 사이트를 처리한 렌더러 프로세스는 unload와 같은 이벤트를 처리하기 위해 유지&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ 서비스 워커&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최근에&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;a style=&quot;color: #04beb8;&quot; href=&quot;https://developer.chrome.com/docs/workbox/service-worker-overview?hl=ko&quot;&gt;서비스 워커&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가 도입&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;되며 내비게이션 과정에도 변화가 생겼음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스 워커는 애플리케이션의 코드에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 프록시&lt;/b&gt;(&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;클라이언트와 서버 간의 중계 역할을 하는 컴퓨터 시스템이나 응용 프로그램&lt;/span&gt;)를 작성할 수 있는 수단&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스 워커를 통해 웹 개발자는 무엇을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;로컬 캐시에 저장&lt;/b&gt;할지, 언제&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크에서 새 데이터를 가져올지 제어&lt;/b&gt;할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스 워커가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;캐시에서 페이지를 로드하도록 설정&lt;/b&gt;되었다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크에서 데이터를 가져오도록 요청할 필요가 없음&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기억해야 할 중요한 점은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서비스 워커&lt;/b&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;렌더러 프로세스에서 실행되는 JavaScript 코드&lt;/b&gt;라는 점&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그렇다면 내비게이션 요청이 들어왔을 때 브라우저 프로세스는 사이트에 서비스 워커가 있다는 것을 어떻게 알 수 있을까?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kYdvZ/btsHRvdBfTR/0cIM77ZkWbn2TuoMTQz7TK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kYdvZ/btsHRvdBfTR/0cIM77ZkWbn2TuoMTQz7TK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kYdvZ/btsHRvdBfTR/0cIM77ZkWbn2TuoMTQz7TK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkYdvZ%2FbtsHRvdBfTR%2F0cIM77ZkWbn2TuoMTQz7TK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;780&quot; height=&quot;495&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PCChm/btsHSsmL5qK/KT12UNsHP5vLximoA6B630/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PCChm/btsHSsmL5qK/KT12UNsHP5vLximoA6B630/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PCChm/btsHSsmL5qK/KT12UNsHP5vLximoA6B630/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPCChm%2FbtsHSsmL5qK%2FKT12UNsHP5vLximoA6B630%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;859&quot; height=&quot;472&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
1. 서비스 워커의 범위를 찾는 브라우저 프로세스의 네트워크 스레드 2. 서비스 워커를 처리할 렌더러 프로세스를 시작하는 브라우저 프로세스의 UI 스레드. 렌더러 프로세스의 워커 스레드가 네트워크에서 데이터를 요청
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스 워커가 등록되면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서비스 워커의 범위는 참조(reference)로 유지&lt;/b&gt;됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;내비게이션이 발생하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;도메인을 등록된 서비스 워커의 범위와 비교&lt;/b&gt;함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;URL에 등록된 서비스 워커&lt;/b&gt;가 있으면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UI 스레드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서비스 워커 코드를 실행하기 위해 렌더러 프로세스를 찾음&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스 워커를 이용하여 네트워크에 데이터를 요청하지 않고 캐시에서 데이터를 가져오거나&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;네트워크에 새 리소스를 요청할 수 있음&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;내비게이션 프리로드&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biGzU5/btsHTmlzcFP/hgjkkk11NZukJCmn4ZKxZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biGzU5/btsHTmlzcFP/hgjkkk11NZukJCmn4ZKxZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biGzU5/btsHTmlzcFP/hgjkkk11NZukJCmn4ZKxZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiGzU5%2FbtsHTmlzcFP%2Fhgjkkk11NZukJCmn4ZKxZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;479&quot; height=&quot;262&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
서비스 워커를 처리할 렌더러 프로세스를 시작하면서 동시에 병렬로 네트워크 요청을 시작하는 브라우저 프로세스의 UI 스레드
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브라우저 프로세스와 렌더러 프로세스 사이를 왕복해야 하는 상황에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서비스 워커&lt;/b&gt;가 결국&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크에서 데이터를 요청&lt;/b&gt;하기로 하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;지연이 발생&lt;/b&gt;하게 됨을 알 수 있음(이리 저리 확인하다 시간을 낭비하는 것)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;내비게이션 프리로드&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서비스 워커의 시작과 병렬로 리소스를 로딩해 내비게이션 과정의 속도를 높이는 메커니즘&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 요청은 헤더에 표시되어 서버가 이러한 요청에 대해 다른 콘텐츠를 보낼 수 있게 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예를 들어 전체 문서를 보내지 않고 업데이트된 데이터만만 보낼 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;헤더에 표시되는것은 처음부터 서비스 워커를 등록할때 내비게이션 프리로드 기능을 사용한다고 명시하면 내비게이션 프리로드가 활성화되어 브라우저가 알아서 내비게이션 요청 헤더를 추가해준다고 함(고마워요 gpt웨건)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #555555; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;div id=&quot;reaction-287&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>CS/브라우저</category>
      <author>H.E</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/132</guid>
      <comments>https://together-cs.tistory.com/132#entry132comment</comments>
      <pubDate>Sat, 8 Jun 2024 20:52:41 +0900</pubDate>
    </item>
    <item>
      <title>ArrayList vs LinkedList</title>
      <link>https://together-cs.tistory.com/130</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;ArrayList 란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList는 배열의 상위호환 버전 정도로 이해하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 배열만으로는 자료를 담고 관리하는데 약간 불편함이 있어서 나온 것이 ArrayList이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList는 내부적으로 배열을 사용하여 구현되어 있지만, 동적으로 배열의 크기를 바꿀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList는 초기에는 일정한 크기의 배열을 생성하고, 요소를 추가할 때마다 내부 배열의 크기를 자동으로 조정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소를 추가할 때 내부 배열이 가득 차게 되면, ArrayList는 현재 배열의 크기를 늘려 더 많은 요소를 수용할 수 있는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 배열을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 기존의 요소들을 새 배열로 복사하고, 새로운 요소를 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 배열의 크기를 동적으로 조정하여 ArrayList가 동적으로 요소를 추가, 제거할 수 있는 구조를 갖게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;LinkedList 란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedList는 데이터가 연속된 위치에 저장되지 않고 모든 데이터가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 부분(= 노드)과 주소 부분(= 포인터)을 가지고 한 줄로 연결되어 있는 방식으로 데이터를 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedList는 노드끼리의 주소 포인터를 서로 가리키며 링크(참조)함으로써 이어지는 구조다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled (1).png&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2H8KW/btsHSea8rve/l6xzvbjouNHqfUXTWFV9Dk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2H8KW/btsHSea8rve/l6xzvbjouNHqfUXTWFV9Dk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2H8KW/btsHSea8rve/l6xzvbjouNHqfUXTWFV9Dk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2H8KW%2FbtsHSea8rve%2Fl6xzvbjouNHqfUXTWFV9Dk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;918&quot; height=&quot;297&quot; data-filename=&quot;Untitled (1).png&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림을 보면 LinkedList는 각기 노드마다 화살표로 연결되어 리스트 형태로 나열되어 있는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 객체를 만들면 객체의 주소가 생기게 되는데, 노드마다 각기 객체의 주소를 서로 참조함으로써 연결 형태를 구성하는 것이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ArrayList vs LinkedList 특징 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedList가 각기 노드를 두고 주소 포인터를 링크하는 식으로 자료를 구성하는 이유는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList가 배열을 이용하여 요소를 저장함으로써 발생하는 단점을 극복하기 위해 고안되었기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100.465%; height: 170px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px; width: 14.7658%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 18px; width: 43.861%;&quot;&gt;ArrayList&lt;/td&gt;
&lt;td style=&quot;height: 18px; width: 41.722%;&quot;&gt;&amp;nbsp;LinkedList&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 14px;&quot;&gt;
&lt;td style=&quot;height: 14px; width: 14.7658%;&quot;&gt;컬렉션 구성&lt;/td&gt;
&lt;td style=&quot;height: 14px; width: 43.861%;&quot;&gt;배열을 이용&lt;/td&gt;
&lt;td style=&quot;height: 14px; width: 41.722%;&quot;&gt;노드를 연결(linked)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 14.7658%;&quot;&gt;데이터 접근 시간&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 43.861%;&quot;&gt;모든 데이터 상수 시간 접근&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 41.722%;&quot;&gt;위치에 따라 이동시간 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 38px; width: 14.7658%;&quot; rowspan=&quot;2&quot;&gt;삽입 / 삭제 시간&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 85.583%;&quot; colspan=&quot;2&quot;&gt;삽입 / 삭제 자체는 상수 시간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 43.861%; height: 18px;&quot;&gt;삽입 / 삭제 시 데이터 이동이 필요한 경우, 추가시간 발생&lt;/td&gt;
&lt;td style=&quot;width: 41.722%; height: 18px;&quot;&gt;삽입 / 삭제 위치에 따라 그 위치까지 이동하는 시간 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;height: 40px; width: 14.7658%;&quot;&gt;리사이징 필요&lt;/td&gt;
&lt;td style=&quot;height: 40px; width: 43.861%;&quot;&gt;공간이 부족할 경우 새로운 배열에 복사하는 추가 시간 발생&lt;/td&gt;
&lt;td style=&quot;height: 40px; width: 41.722%;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;height: 40px; width: 14.7658%;&quot;&gt;데이터 검색&lt;/td&gt;
&lt;td style=&quot;height: 40px; width: 85.583%;&quot; colspan=&quot;2&quot;&gt;최악의 경우 리스트에 있는 아이템 수 만큼 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ArrayList의 문제점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList는 배열 공간(capacity)이 꽉 차거나, 요소 중간에 삽입을 행하려 할 때, &lt;br /&gt;기존의 배열을 복사해서 요소를 뒤로 한칸씩 일일히 이동해야 하는 작업이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 부가적인 연산은 시스템의 성능 저하로 이어져 삽입/삭제가 빈번하게 발생하는 프로세스의 경우, 치명적일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 자료들이 지속적으로 삭제되는 과정에서 ArrayList에서는 그 공간만큼 낭비되는 메모리가 많아지게 되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 리사이징 처리에서 시간이 소모된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img1.daumcdn.png&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ3Yrc/btsHR1Xjj4t/o9Yyjdbok9gn7SQXVDxKl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ3Yrc/btsHR1Xjj4t/o9Yyjdbok9gn7SQXVDxKl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ3Yrc/btsHR1Xjj4t/o9Yyjdbok9gn7SQXVDxKl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ3Yrc%2FbtsHR1Xjj4t%2Fo9Yyjdbok9gn7SQXVDxKl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;979&quot; height=&quot;357&quot; data-filename=&quot;img1.daumcdn.png&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;LinkedList의 장단점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedList는 불연속적으로 존재하는 데이터를 서로 연결한 형태로 구성되어있기 때문에 공간의 제약이 존재하지 않으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삽입 역시 노드가 가리키는 포인터만 바꿔주면 되기 때문에 배열처럼 데이터를 이동하기 위해 복사하는 과정이 없어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삽입/삭제 처리 속도가 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 삽입/삭제가 자주 발생하는 프로세스의 경우 LinkedList를 사용하여 시스템을 구현하는 것이 바람직하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 LinkedList에도 만능이 아니며 단점이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소를 get하는 과정에서 ArrayList와 굉장한 성능 차이를 보이는데, ArrayList에서는 무작위 접근(random access)이 가능하지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedList에서는 순차 접근(sequential access)만이 가능하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 n개의 자료를 저장할 때, ArrayList는 자료들을 하나의 연속적인 묶음으로 묶어 자료를 저장하는 반면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedList는 자료들을 저장 공간에 불연속적인 단위로 저장하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 그림으로 표현하자면, 아래 빌딩 그림을 메모리(RAM)으로 비유하고 각기 방을 데이터라고 비유하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList는 연속적인 묶음으로 되어있지만, LinkedList는 각기 다른 방에 저장되어 있고 링크로 연결되어 있음을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img1.daumcdn-1.png&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clijfc/btsHR6RJdN2/TTZ6z0aoJNJ2lN36ZqaKl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clijfc/btsHR6RJdN2/TTZ6z0aoJNJ2lN36ZqaKl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clijfc/btsHR6RJdN2/TTZ6z0aoJNJ2lN36ZqaKl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fclijfc%2FbtsHR6RJdN2%2FTTZ6z0aoJNJ2lN36ZqaKl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;849&quot; height=&quot;568&quot; data-filename=&quot;img1.daumcdn-1.png&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 LinkedList는 메모리 이곳저곳에 산재해 저장되어 있는 노드들을 접근하는데 있어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList보다 당연히 긴 지연 시간이 소모되게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinekdList의 또 다른 단점은 참조자를 위해 추가적인 메모리를 할당해야 한다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 같은 경우 그냥 데이터 그대로만 저장하면 되지만, LinkedList의 노드 같은 경우 데이터 이외에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next나 prev 같은 참조자도 저장해야 되기 때문에 추가적인 공간이 더 필요할 수 밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- LinkedList 장단점 표.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;LinkedList 장점&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&amp;nbsp;LinkedList 단점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;자료의 삽입과 삭제가 용이&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;포인터의 사용으로 인해 저장 공간의 낭비&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;리스트 내에서 자료의 이동이 불필요&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;알고리즘이 복잡&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;사용 후 기억 장소의 재사용이 가능&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;특정 자료의 탐색 시간이 많이 소요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;연속적인 기억 장소의 할당이 불필요&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ArrayList vs LinkedList 성능 비교&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시간 복잡도 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedList에 대해 착각하는 것이 요소를 추가하는 것과 요소가 삭제하는 것의 시간 복잡도가 오로지 O(1)이라는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 압이나 맨 뒤 요소만 추가하고 삭제한다고 가정하면 맞지만, 중간에 요소를 추가/삭제한다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중간 위치까지 탐색을 해야 하므로 최종적으로 O(N)이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 140px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;연산&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&amp;nbsp;양방향 LinkedList(doubly)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&amp;nbsp;ArrayList&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&amp;nbsp;추천&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;첫번째 위치에 insert / remove&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(N)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;LinkedList&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;마지막 위치에 insert / remove&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(1) / O(N)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;LinkedList&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;중간에 insert / remove&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(N) / search time + O(1)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(N)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;LinkedList&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;값으로 search&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(N)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(N)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;ArrayList&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;인덱스로 값 get&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(N)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;ArrayList&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;값으로 remove&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(N)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;O(N)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;LinkedList&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 표에서 ArrayList에서 첫번째 삽입이 O(N)인 이유는 무조건적으로 요소들을 뒤로 이동해야 되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 마지막 위치 삽입이 O(1) 또는 O(N)이 되는 이유는 만일 공간 부족으로 인해 배열 복사가 일어나면 시간이 소요되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실제 성능 측정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회(get) 시에는 ArrayList가 우위지만 삽입 / 삭제(add/remove) 시에는 LinkedList가 뛰어난 성능을 보여준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img1.daumcdn-2.png&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;431&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BsvfP/btsHSqvtVL5/VcQ9RCpNNPzZVyyP1Wnuwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BsvfP/btsHSqvtVL5/VcQ9RCpNNPzZVyyP1Wnuwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BsvfP/btsHSqvtVL5/VcQ9RCpNNPzZVyyP1Wnuwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBsvfP%2FbtsHSqvtVL5%2FVcQ9RCpNNPzZVyyP1Wnuwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;431&quot; data-filename=&quot;img1.daumcdn-2.png&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;431&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[순차 추가] LinkedList&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: &lt;span style=&quot;background-color: #f89009;&quot;&gt;LinkedList가 우위&lt;/span&gt;인 이유는 ArrayList는 공간 부족으로 인한 배열 복사가 일어나기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[중간 추가] LinkedList&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: &lt;span style=&quot;background-color: #f89009;&quot;&gt;LinkedList가 우위&lt;/span&gt;인 이유는 ArrayList는 배열 복사 및 데이터 이동이 발생하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[접근 시간] ArrayList&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: &lt;span style=&quot;background-color: #f89009;&quot;&gt;ArrayList가 우위&lt;/span&gt;인 이유는 메모리 저장 구조상 배열은 연속된 공간에 저장되고 인덱스로 단번에 엑세스하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[중간 삭제] LinkedList&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: &lt;span style=&quot;background-color: #f89009;&quot;&gt;LinkedList가 우위&lt;/span&gt;인 이유는 요소 이동없이 그저 노드의 포인팅만 교체만 하면 되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[순차 삭제] ArrayList&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: &lt;span style=&quot;background-color: #f89009;&quot;&gt;ArrayList가 우위&lt;/span&gt;인 이유는 노드의 링크를 끊고 하는 작업보단 배열에서 요소를 삭제하는게 더 빠르기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;LinkedList는 의외로 잘 사용되지 않는다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 ArrayList와 LinkedList 중에 어느걸 사용하면 되냐고 묻는다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삽입/삭제가 빈번하면 LinkedList를, 요소를 가져오기가 빈번하면 ArrayList를 사용하면 된다고 하지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 성능면에서 둘은 큰 차이가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, ArrayList는 리사이징 과정에서 배열 복사하는 추가 시간이 들지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열을 새로 만들고 for문을 돌려 기존 요소를 일일히 대입하는 것이 아닌 내부적으로 잘 튜닝이 되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최적화가 되어있어 생각하는 것처럼 전혀 느리지 않다.&lt;/p&gt;</description>
      <category>CS/프로그래밍</category>
      <category>ArrayList</category>
      <category>LinkedList</category>
      <author>하계동물고기</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/130</guid>
      <comments>https://together-cs.tistory.com/130#entry130comment</comments>
      <pubDate>Fri, 7 Jun 2024 23:52:11 +0900</pubDate>
    </item>
    <item>
      <title>ZUSTAND</title>
      <link>https://together-cs.tistory.com/124</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmRo9Z/btsHznSxxu8/hi3wOnUqtTx0A6yDzfNi7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmRo9Z/btsHznSxxu8/hi3wOnUqtTx0A6yDzfNi7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmRo9Z/btsHznSxxu8/hi3wOnUqtTx0A6yDzfNi7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmRo9Z%2FbtsHznSxxu8%2Fhi3wOnUqtTx0A6yDzfNi7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;467&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ZUSTAND에 관심을 갖게 된 이유&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2706&quot; data-origin-height=&quot;924&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vGYTg/btsHxpxZp9c/PzgFsO4tGUhKnzfvDYpxi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vGYTg/btsHxpxZp9c/PzgFsO4tGUhKnzfvDYpxi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vGYTg/btsHxpxZp9c/PzgFsO4tGUhKnzfvDYpxi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvGYTg%2FbtsHxpxZp9c%2FPzgFsO4tGUhKnzfvDYpxi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2706&quot; height=&quot;924&quot; data-origin-width=&quot;2706&quot; data-origin-height=&quot;924&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm trends에 따르면 redux 다음으로 가장 핫한 상태관리 라이브러리,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꾸준하게 상승중이고 상승폭도 가장 커 다음 프로젝트에는 Zustand를 사용해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 ZUSTAND가 핫할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://zustand-demo.pmnd.rs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://zustand-demo.pmnd.rs/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1716369690688&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Zustand&quot; data-og-description=&quot;&quot; data-og-host=&quot;zustand-demo.pmnd.rs&quot; data-og-source-url=&quot;https://zustand-demo.pmnd.rs/&quot; data-og-url=&quot;https://zustand-demo.pmnd.rs/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://zustand-demo.pmnd.rs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://zustand-demo.pmnd.rs/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Zustand&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;zustand-demo.pmnd.rs&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 직관적이고 간편한 사용법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ZUSTAND 메인페이지와 Documentation에서 사용법을 살펴보면&lt;/p&gt;
&lt;pre id=&quot;code_1716369767309&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install zustand&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716369803649&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { create } from 'zustand'

const useStore = create((set) =&amp;gt; ({
  count: 1,
  inc: () =&amp;gt; set((state) =&amp;gt; ({ count: state.count + 1 })),
}))

function Counter() {
  const { count, inc } = useStore()
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;span&amp;gt;{count}&amp;lt;/span&amp;gt;
      &amp;lt;button onClick={inc}&amp;gt;one up&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 끝.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 쉽게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 작은 크기&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGO3Cu/btsHxY7wz8u/yTHoXbNc3LEiwMASnKSGo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGO3Cu/btsHxY7wz8u/yTHoXbNc3LEiwMASnKSGo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGO3Cu/btsHxY7wz8u/yTHoXbNc3LEiwMASnKSGo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGO3Cu%2FbtsHxY7wz8u%2FyTHoXbNc3LEiwMASnKSGo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;328&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux, Recoil 보다 훨씬 작은 사이즈를 가져 가볍고 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 중복 렌더링 최소화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ZUSTAND는 상태 업데이트 시 중복 렌더링을 최소화하여 성능 최적화에 유리,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태가 변경되더라도 관련된 컴포넌트만 업데이트 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;하루가 멀다하고 바뀌는 프론트엔드 기술..&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;핫한 것만 따라갑시다이-&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;저는 이번에 포폴 만들 때 요걸 사용해볼까 생각 중&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;사용법은 제가 실제로 사용해보고 요기다가 업데이트 할게요&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS/프레임워크&amp;amp;라이브러리</category>
      <author>jay-dev</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/124</guid>
      <comments>https://together-cs.tistory.com/124#entry124comment</comments>
      <pubDate>Wed, 22 May 2024 18:37:14 +0900</pubDate>
    </item>
    <item>
      <title>jquery를 사용하지 않게 된 이유</title>
      <link>https://together-cs.tistory.com/123</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[ jQuery ]&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;jQuery는 JS를 작성하는것은 재밌어야 한다는 모토를 가진 JS 라이브러리&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;적게 쓰고 많은 일을 하게(write less, do more)&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;도와주는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;JS 라이브러리&lt;/b&gt;&lt;/span&gt;라고 생각하면 됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일반적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;반&lt;/b&gt;&lt;b&gt;복적인 작업을 수행하고 불필요한 마크업을 제거, 짧고 이해하기 쉬운 코드를 작성할 수 있게 해줌&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예를 들어 jQuery가 등장하기 이전에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://developer.mozilla.org/ko/docs/Web/API/XMLHttpRequest&quot;&gt;XMLHttpRequest&lt;/a&gt;를 사용하여 비동기 통신을 처리해야 했음&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716212809848&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;let xhr = new XMLHttpRequest();
xhr.open('POST', '/test');
xhr.send();
xhr.onload = function () {
  if (xhr.status != 200) {
    console.error(`${xhr.status}: ${xhr.statusText}`);
  } else {
    console.log(xhr.response);
  }
};
xhr.onprogress = function (event) {
  if (event.lengthComputable) {
    console.error(`Received ${event.loaded} of ${event.total} bytes`);
  } else {
    console.error(`Received ${event.loaded} bytes`);
  }
};
xhr.onerror = function () {
  console.error('Request failed');
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만 jQuery의 Ajax를 이용하면 코드가 훨씬 간단해짐&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716212809849&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;$.ajax({
  type: 'post',
  url: '/test',
  async: true,
  headers: {
    'Content-Type': 'application/json',
  },
  dataType: 'text',
  data: JSON.stringify({
    id: id,
    name: name,
  }),
  success: function (result) {
    console.log(result);
  },
  error: function (request, status, error) {
    console.error(error);
  },
});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ jQuery 특징&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTML/DOM 조작: HTML 요소를 쉽게 선택하고 조작할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이벤트 처리: 다양한 이벤트를 간단하게 처리할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;크로스 브라우징: 다양한 브라우저 간 호환성 문제를 해결해 줌&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;애니메이션: 간단한 애니메이션 효과를 쉽게 구현할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메소드 체이닝(Method chaining) 등 짧고 유지관리가 용이한 코드 작성을 지원&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;플러그인: 플러그인을 쉽게 구현하거나 확장할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ jQuery를 사용하지 않게 된 이유&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;jQuery는 초기 웹 개발 환경에서 큰 혁신을 가져왔으나, 시간이 지나면서 몇 가지 한계가 드러남&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;성능 최적화 문제와 유지보수의 어려움이 그 주요 원인&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;성능 문제&lt;/b&gt;: jQuery는 Vanilla JS에 비해 로드해야 할 패키지가 많아 간단한 코드를 작성하더라도 성능적으로 떨어짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유지보수 어려움&lt;/b&gt;: jQuery는 모듈화나 컴포넌트화와는 거리가 있어 대규모 애플리케이션에서 유지보수하기 쉽지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;브라우저 성능 저하&lt;/b&gt;: 현대의 웹 애플리케이션에서는 사용자에 의한 동적인 DOM 조작이 잦음 jQuery를 이용하면 배치와 화면 표시 과정에서 많은 연산이 발생해 브라우저 성능이 저하되는 문제가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 외에도&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;웹 표준 API의 확장 : 제이쿼리가 없어도 쉽게 사용 가능해진 웹 api&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;웹 표준이 개선&lt;/b&gt;&lt;/span&gt;되어 여러 브라우저는 표준을 지키는 방향으로 나아가고 있음&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;이런 노력으로&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://developer.mozilla.org/ko/docs/Web/API&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;WEB API&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;가 발전&lt;/span&gt;&lt;/b&gt;하였음&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;fetch API, DOM API&lt;/b&gt;&lt;/span&gt;(classList, querySelector, querySelectorAll)와 같은 jQuery의 대체제가 등장함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;예를 들어 위에 비동기 통신 예시를 fetch를 사용하면 훨씬 간단해짐&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716212809851&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;fetch('/test', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    id: id,
    name: name,
  }),
})
  .then(response =&amp;gt; console.log(response))
  .catch(error =&amp;gt; console.error(error));&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;웹브라우저 환경의 변화 : 빨라진 자바스크립트 성능과 브라우저 호환성이 좋아짐&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;초기 웹 개발에서 jQuery는 다양한 브라우저 간의 호환성 문제를 해결&lt;/b&gt;&lt;/span&gt;하는데 큰 역활을 했지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;최신 브라우저들은 대부분&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://ecma-international.org/publications-and-standards/standards/ecma-262/&quot;&gt;ECMScript 표준&lt;/a&gt;을 잘 준수&lt;/span&gt;&lt;/b&gt;하고 있어 이러한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;호환성 문제가 크게 감소&lt;/b&gt;&lt;/span&gt;하게 됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;제이쿼리가 본격적으로 인기를 얻기 시작했던 2007~2008년에는 인터넷 익스플로러가 웹브라우저 시장에서 점유율이 가장 높았고, 인터넷 익스플로러는 버전 업데이트 속도가 느리고 데스크톱 기반의 윈도우 운영체제에 주력했다는 특징이 있어 생산성과 가독성이 높은 코드를 작성하기 위해 제이쿼리가 사용되었음&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;하지만 윈도우, 맥 등 데스크톱 OS와 모바일 OS까지 지원하는 크롬이 등장하며 점유율을 높게 장악했는데 크롬은 빠른 버전 업데이트를 추구하여 웹 표준을 신속하게 반영함&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;가상 돔을 사용하는 라이브러리의 등장&amp;nbsp;: 성능적으로 개선된 방법인 가상돔을 사용하는 라이브러리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;React와 같은 라이브러리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;가상 DOM&lt;/b&gt;&lt;/span&gt;을 사용하여 웹 애플리케이션의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;성능을 크게 향상&lt;/b&gt;&lt;/span&gt;시켰음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;가상 DOM은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0d0d0d; text-align: start;&quot;&gt;실제 DOM 조작을 최소화하여 애플리케이션의 성능을 높이며&lt;/span&gt;&lt;span style=&quot;color: #0d0d0d; text-align: start;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;jQuery가 제공하지 못하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;선언적이고 모듈화된 프로그래밍 패러다임을 제공&lt;/b&gt;&lt;/span&gt;함&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;이를 통해 개발자는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;더 효율적이고 유지보수하기 쉬운 코드를 작성&lt;/b&gt;&lt;/span&gt;할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;▶ React와 jQuery&amp;nbsp; 비교&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;React와 jQuery의 가장 중요한 차이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;가상돔 사용&lt;/b&gt;&lt;/span&gt;과&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;컴포넌트 기반 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;dom-컨트롤&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;DOM 컨트롤&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;React는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;가상 DOM&lt;/b&gt;&lt;/span&gt;을 사용하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;실제 DOM 조작을 최소화하고 성능을 향상&lt;/b&gt;&lt;/span&gt;시킴&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;jQuery는 우선 최초로 DOM 을 찾으려면 document 에서부터 쭉 타고 내려오면서 찾아야함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이렇게 되면 원하는 태그를 찾을 때까지 최상단 엘리먼트에서 트리 탐색을하며 내려오니까 더 많은 검색이 발생함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;실제 DOM을 직접 조작&lt;/b&gt;&lt;/span&gt;하므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;더 많은 DOM 조작이 필요한 등의 성능 저하가 발생&lt;/b&gt;&lt;/span&gt;함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;예를들어 document.getElementById('myDiv')로 간단하게 찾는 한줄코딩이라면, jQuery는 수없이 많이 랩핑된 소스에서 $('#myDiv')을 찾게 됨으로써&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;불필요한 리소스로 인한 동작의 저하&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;가 발생 할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;컴포넌트-기반-아키텍처&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;컴포넌트 기반 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;React는 컴포넌트를 사용하여 UI를 작성하고 관리하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;각 컴포넌트는 독립적으로 작동하며 재사용 가능&lt;/b&gt;&lt;/span&gt;함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;코드 모듈화&lt;/b&gt;&lt;/span&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;유지 보수를 용이&lt;/b&gt;&lt;/span&gt;하게 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;jQuery&lt;/b&gt;는 이러한 컴포넌트 기반 아키텍처를 제공하지 않으며, 코드는 주로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;이벤트 핸들러와 DOM 조작 함수&lt;/b&gt;&lt;/span&gt;로 이루어져 있음 따라서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;모든 로직이 한 곳에 집중되어 있어 코드가 길어지고 유지보수하기 어려움&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;처음에는 단순히 jQuery가 무엇인지, 왜 요즘에는 덜 사용되는지를 알고 싶었지만, 실제로 조사해보니 웹 개발 환경의 변화와 기술 발전이 얼마나 빠르고 다채롭게 이루어지고 있는지를 알게 됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;jQuery는 처음에는 웹 개발에 혁신을 가져온 도구였음 단순하고 직관적인 API로 복잡한 DOM 조작을 쉽게 만들고, 다양한 브라우저 간의 호환성 문제를 해결해주었기 때문 하지만 웹 표준 API의 발전과 브라우저 성능의 향상, 그리고 React와 같은 가상 DOM을 사용하는 라이브러리의 등장은 jQuery를 뒤편으로 보내버림&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;React의 컴포넌트 기반 아키텍처와 가상 DOM의 도입은 코드의 재사용성과 유지보수성을 크게 향상시켰음 이러한 기술적 발전은 단순히 새로운 도구를 사용하는 것을 넘어, 전체적인 개발 패러다임의 변화를 가져옴 예를 들어, React의 컴포넌트 기반 구조는 대규모 애플리케이션에서도 코드의 모듈화와 재사용을 용이하게 하고, 선언적 프로그래밍 스타일은 상태 관리와 UI 갱신을 더욱 직관적으로 만들어 줌&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결국, 기술은 끊임없이 발전하고 변화함 jQuery가 혁신적이었던 시절이 있었듯이, 현재는 React와 같은 가상 돔을 사용하는 라이브러리가 그 자리를 차지하고 있음 이러한 변화 속에서 중요한 것은 트렌드를 새롭게 갱신하고 새로운 기술을 배우고 적응하며, 이를 통해 더욱 효율적이고 생산적인 개발을 할 수 있는 능력이 필요하다는 것을 다시 한번 느낌 앞으로도 계속해서 변화하는 웹 개발 환경을 주시하며, 최신 기술을 습득하고 적용할 수 있도록 노력해야 겠음&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS/프레임워크&amp;amp;라이브러리</category>
      <author>H.E</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/123</guid>
      <comments>https://together-cs.tistory.com/123#entry123comment</comments>
      <pubDate>Mon, 20 May 2024 22:20:46 +0900</pubDate>
    </item>
    <item>
      <title>Jotai</title>
      <link>https://together-cs.tistory.com/120</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Jotai&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Jotai는&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;React State Management Libarary&lt;/b&gt;&lt;/span&gt;&amp;nbsp;중 하나이고 Recoil, Redux와 같이 상태 관리에 필요한 편의 기능을 제공하는 라이브러리&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Jotai는 Recoil과 같은 Atomic 접근 방식으로 React에서 사용되는 state와 비슷하게 리액트 트리 안에서 상태를 저장하고 관리하는 방법임&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Jotai 특징&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://jotai.org/&quot;&gt;https://jotai.org/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715166896633&quot; style=&quot;color: #555555; text-align: start;&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bOTUyp/hyVZr2b6GS/0WcdxNi8LnfgOM1LVmGtKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bhOpOw/hyV2CHLHE6/v8U1n9lb9lAvPkipxtOwbk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/8y1ho/hyVZe9zHKQ/S6l6eCk1QaEoWyaNoYrZiK/img.png?width=225&amp;amp;height=205&amp;amp;face=0_0_225_205&quot; data-og-url=&quot;https://jotai.org&quot; data-og-source-url=&quot;https://jotai.org/&quot; data-og-host=&quot;jotai.org&quot; data-og-description=&quot;Jotai takes a bottom-up approach to global React state management with an atomic model inspired by Recoil. One can build state by combining atoms and renders are optimized based on atom dependency. This solves the extra re-render issue of React context and&quot; data-og-title=&quot;Jotai, primitive and flexible state management for React&quot; data-og-type=&quot;website&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://jotai.org/&quot; data-source-url=&quot;https://jotai.org/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bOTUyp/hyVZr2b6GS/0WcdxNi8LnfgOM1LVmGtKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bhOpOw/hyV2CHLHE6/v8U1n9lb9lAvPkipxtOwbk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/8y1ho/hyVZe9zHKQ/S6l6eCk1QaEoWyaNoYrZiK/img.png?width=225&amp;amp;height=205&amp;amp;face=0_0_225_205');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Jotai, primitive and flexible state management for React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Jotai takes a bottom-up approach to global React state management with an atomic model inspired by Recoil. One can build state by combining atoms and renders are optimized based on atom dependency. This solves the extra re-render issue of React context and&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jotai.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;Jotai 공식문서에 따르며 Recoil에서 영감을 받아 React 상태 관리에 대한 원자적 접근 방식을 취하는 도구이며&lt;/span&gt;&amp;nbsp;원자 종속성에 따라 자동으로 최적화되고&amp;nbsp;매우 최소한의 API를 가지고 있으며&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;useState의 간단한 대체부터 복잡한 요구 사항이 있는 엔터프라이즈 TypeScript 애플리케이션까지 확장 가능하며, 다양한 유틸리티와 통합 기능을 제공한다고 나와있음&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;특징을 정리해보면&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;background-color: #f6e199; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;작은 번들 크기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Recoil에서 영감을 받아&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;아토믹( Atomic)&lt;/b&gt;&lt;/span&gt;&amp;nbsp;모델과 함께&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;상향식 접근(Bottom-up)&lt;/b&gt;&lt;/span&gt;&amp;nbsp;방식으로 접근&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;아톰&lt;/b&gt;&lt;/span&gt;과 함께 상태를 생성하고&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;렌더링 최적화&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;리액트 context의 Re-rendering 이슈를 해결하고 메모이제이션(memorization)의 의존도를 줄일 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;React의&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Context(useState + useContext) 기반 상태관리 모델&lt;/b&gt;&lt;/span&gt;에서 발생한 주요 이슈들의 개선에 초점을 맞춤&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Recoil보다 선호되는 이유&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;경량화된 API&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;String key의 미사용&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;TypeScript&lt;/b&gt;&amp;nbsp;기반&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;utils 함수&lt;/b&gt;들의 제공&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Jotai는 언제 사용할까?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;작은 규모의 프로젝트&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redux나 MobX와 같은 다른 상태 관리 라이브러리보다 상대적으로 작음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;간단한 상태 관리&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redux나 MobX와 같은 상태 관리 라이브러리에 비해 보다 단순하고 직관적인 API를 제공&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;별도의 라이브러리를 사용하지 않아도 됨&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Context API와 함께 작동하며, Context API의 간편한 사용법을 이용하여 상태관리를 할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Jotai 사용&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;atom()&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1715166896635&quot; class=&quot;javascript&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { atom } from 'jotai';

const priceAtom = atom(10); // number
const messageAtom = atom('hello'); // string
const productAtom = atom({ id: 12, name: 'good stuff' }); // object
const citiesAtom = atom(['Tokyo', 'Kyoto', 'Osaka']); // array&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;jotail의 내장 API&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;상태의 단위(조각)&lt;/span&gt;&lt;/b&gt;이자&amp;nbsp;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;state를 생성&lt;/span&gt;&lt;/b&gt;하는 함수&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Recoil과 달리&amp;nbsp;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;key값(string)을 설정하지 않음&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;읽기 / 쓰기 전용 atom&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1715166896636&quot; class=&quot;typescript&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { atom } from 'jotai';

const priceAtom = atom(10);

const readOnlyAtom = atom((get) =&amp;gt; get(priceAtom) * 2);
const writeOnlyAtom = atom(
  null, // 첫 번째 인자로 전달하는 초기값은 null
  (get, set, update) =&amp;gt; {
    // update는 atom을 업데이트하기 위해 받아오는 값
    set(priceAtom, get(priceAtom) - update.discount)
  }
);

const readWriteAtom = atom(
  (get) =&amp;gt; get(priceAtom) * 2,
  (get, set, newPrice) =&amp;gt; {
    set(proceAtom, newPrice / 2)
    // set 로직은 원하는 만큼 지정할 수 있음
  }
);

// 읽기(read)
import { useAtomValue } from 'jotai';
const count = useAtomValue(countAtom);

// 쓰기(write)
import { useSetValue } from 'jotai';
const count = useSetValue(countAtom);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;읽기 전용(Read-only)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쓰기 전용(Write-only)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;읽기,쓰기 전용(Read-Write)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;useAtom()&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;useAtom 훅은 atom을 인자로 받아, [atom, setAtom]&amp;nbsp;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;값과 세터함수를 튜플로 반환&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;상태를 적용하고자 하는 컴포넌트 내에서 useAtom을 import해서 상태 &amp;amp; 세터함수를 선언해주면 됨&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715166896637&quot; class=&quot;javascript&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { useAtom } from 'jotai';
import { countAtom } from '../store';

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  return (
    &amp;lt;div&amp;gt;
      {count}
      &amp;lt;button onClick={() =&amp;gt; setCount(c =&amp;gt; c + 1)}&amp;gt;+1&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Async&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; color: #000000;&quot;&gt;&lt;b&gt;Jotai는 atom이 동기/비동기를 모두 담당&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;초기 fetch를 위해 write 함수인자를 활용하면 됨&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715166896637&quot; class=&quot;dart&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fetchUrlAtom = atom(async (get) =&amp;gt; {
  const response = await fetch(get('https://my-api.com'));
  return await response.json();
})&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;비동기 상태 fetch간 노출할 목적으로,&amp;nbsp;&lt;b&gt;&amp;lt;Suspense&amp;gt; 컴포넌트로 감싸서 fallback을 설정&lt;/b&gt;해줘야 함&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715166896638&quot; class=&quot;javascript&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const App = () =&amp;gt; (
  &amp;lt;Proveider&amp;gt;
    &amp;lt;Suspense fallback=&quot;Loading...&quot;&amp;gt;
      &amp;lt;Layout /&amp;gt;
    &amp;lt;/Suspense&amp;gt;
  &amp;lt;/Provider&amp;gt;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Utils&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Jotai에서 유용한&amp;nbsp;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;유틸을 제공&lt;/span&gt;&lt;/b&gt;해줌&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;리셋이나 스토리지 저장 등&lt;/b&gt;&amp;nbsp;다양한 메서드가 들어있음&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715166896639&quot; class=&quot;javascript&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { atom, useAtom } from 'jotai';
import { useAtomValue, useUpdateAtom } from 'jotai/utils';

const exampleAtom = atom(0);

const Example = (0 =&amp;gt; {
  // 기존 useAtom
  const [myAtom, setMyAtom] = useAtom(exampleAtom);
  
  // useAtomValue, useUpdateAtom 각각 적용
  connst myAyom = useAtomValue(exampleAtom);
  const setMyAtom = useUpdateAtom(exampleAtom);
  
  return &amp;lt;div&amp;gt;atom: {myAtom}&amp;lt;/div&amp;gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;AtomWithStorage&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;atom 상태값을 스토리지에 저장&lt;/span&gt;&lt;/b&gt;하는 유틸리티 함수. 토큰 등 스토리지와 연관되는 전역상태에 유용&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;인자는 키네임, 값, 옵션을 받으며, 옵션의 기본값은 localStorage&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715166896640&quot; class=&quot;coffeescript&quot; style=&quot;color: #555555; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const anAtom = atomWithStorage('Is_key', [], {
  ...createJSONStorage(() =&amp;gt; localStorage),
  delayInit: true,
})&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CS/프로그래밍</category>
      <author>H.E</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/120</guid>
      <comments>https://together-cs.tistory.com/120#entry120comment</comments>
      <pubDate>Wed, 8 May 2024 20:15:00 +0900</pubDate>
    </item>
    <item>
      <title>AWS S3 + CloudFront 배포</title>
      <link>https://together-cs.tistory.com/119</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;개요&lt;br /&gt;&lt;br /&gt;1. AWS IAM 설정&lt;br /&gt;2. S3 생성 및 설정&lt;br /&gt;3. CloudFront 설정&lt;br /&gt;4. Github Action으로 CI / CD 구축&lt;/b&gt;&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;✅ AWS IAM 설정&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;  IAM(Identity and Access Management)이란?&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;AWS리소스에 대한 엑세스를 안전하게 제어할 수 있는 웹 서비스로 AWS 계정을 최초로 생성할 때 만들어지는 루트 사용자는 모든 엑세스 권한을 가지기에 보안에 주의해서 사용해야하므로 IAM을 통해 리소스를 사용할 수 있는 인증 및 권한 부여된 대상을 제어한다.&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리소스에 대해 여러 사람에게 다양한 권한을 부여할 수 있다.&lt;/li&gt;
&lt;li&gt;사용자에게 직접 정책을 설정할 수도 있지만 그룹에 대해서도 부여할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;  IAM 사용자 추가하기&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AWS &amp;gt; IAM &amp;gt; 사용자 생성 &amp;gt; 1 ~3단계 수행 &amp;gt; 생성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNA7N9/btsHgo6VO9I/gEU0gKHSK8L98b3E6GdK3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNA7N9/btsHgo6VO9I/gEU0gKHSK8L98b3E6GdK3k/img.png&quot; style=&quot;width: 55.2326%; margin-right: 10px;&quot; width=&quot;906&quot; height=&quot;510&quot; data-widthpercent=&quot;55.88&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;495&quot; data-filename=&quot;iam1.png&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNA7N9/btsHgo6VO9I/gEU0gKHSK8L98b3E6GdK3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNA7N9%2FbtsHgo6VO9I%2FgEU0gKHSK8L98b3E6GdK3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;879&quot; height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnnDSH/btsHjbZklCH/5AEKXkX4rhkYOYNXe66gek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnnDSH/btsHjbZklCH/5AEKXkX4rhkYOYNXe66gek/img.png&quot; style=&quot;width: 43.6047%;&quot; data-widthpercent=&quot;44.12&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;627&quot; data-filename=&quot;iam2.png&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnnDSH/btsHjbZklCH/5AEKXkX4rhkYOYNXe66gek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnnDSH%2FbtsHjbZklCH%2F5AEKXkX4rhkYOYNXe66gek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;879&quot; height=&quot;627&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;IAM 생성 + 그룹에 사용자 추가하기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;S3FullAccess, CloudFrontFullAccess&amp;nbsp;&lt;/b&gt;두개의 권한 옵션을 설정해준다.&lt;/li&gt;
&lt;li&gt;IAM을 통해 발급 받는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;access key&lt;/b&gt;는 추후에 자주 사용되므로 꼭 발급 받자&lt;/li&gt;
&lt;li&gt;이때 그룹은 권합 옵션을 공유해주는 집단이므로 프로젝트 팀명으로 구분이 쉽게 하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qLzut/btsHgcyVe6w/DUYXfhxVrrqmOCLLqyYwn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qLzut/btsHgcyVe6w/DUYXfhxVrrqmOCLLqyYwn0/img.png&quot; style=&quot;width: 56.5694%; margin-right: 10px;&quot; width=&quot;398&quot; data-widthpercent=&quot;57.23&quot; data-filename=&quot;ack.png&quot; data-origin-height=&quot;1015&quot; data-origin-width=&quot;902&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qLzut/btsHgcyVe6w/DUYXfhxVrrqmOCLLqyYwn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqLzut%2FbtsHgcyVe6w%2FDUYXfhxVrrqmOCLLqyYwn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;902&quot; height=&quot;1015&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZV8OF/btsHgWI69df/N7kO3TiFp5LoLvP7c4QVYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZV8OF/btsHgWI69df/N7kO3TiFp5LoLvP7c4QVYK/img.png&quot; style=&quot;width: 42.2678%;&quot; width=&quot;406&quot; data-widthpercent=&quot;42.77&quot; data-filename=&quot;ack2.png&quot; data-origin-height=&quot;1000&quot; data-origin-width=&quot;664&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZV8OF/btsHgWI69df/N7kO3TiFp5LoLvP7c4QVYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZV8OF%2FbtsHgWI69df%2FN7kO3TiFp5LoLvP7c4QVYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;664&quot; height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;access key 발급&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;✅  S3 생성 및 설정&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;  S3(Simple Storage Service)란?&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;인터넷 스토리지 서비스로 데이터를 객체 형태로 저장하는 파일 저장 서비스이며, 주로 이미지, 동영상 파일 저장을 위해 사용된다.&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SSL을 통해 데이터를 전송 및 암호화하여 높은 내구성과 보안성을 가지고 있다.&lt;/li&gt;
&lt;li&gt;EC2보다 이미지, 영상을 저장할 때 비용이 저렴하다.&lt;/li&gt;
&lt;li&gt;파일 저장에 최적화 되어 업로드 / 다운로드 속도가 빠르고 정적 웹페이지의 경우 성능을 높이고 비용을 절감할 수 있다.&lt;/li&gt;
&lt;li&gt;저장 용량이 크다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;  S3 버킷 생성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AWS &amp;gt; S3 &amp;gt; 버킷만들기 &amp;gt; 생성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UgJq8/btsHgcZ0b2c/t9T6cnvkFFKJojxCcvwWTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UgJq8/btsHgcZ0b2c/t9T6cnvkFFKJojxCcvwWTK/img.png&quot; style=&quot;width: 42.6579%; margin-right: 10px;&quot; data-widthpercent=&quot;43.16&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;362&quot; data-filename=&quot;bk.png&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UgJq8/btsHgcZ0b2c/t9T6cnvkFFKJojxCcvwWTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUgJq8%2FbtsHgcZ0b2c%2Ft9T6cnvkFFKJojxCcvwWTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;811&quot; height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NCY4f/btsHjeBLMP1/ZuSZKTJWpFErqUZDUKCcH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NCY4f/btsHjeBLMP1/ZuSZKTJWpFErqUZDUKCcH1/img.png&quot; style=&quot;width: 56.1793%;&quot; data-widthpercent=&quot;56.84&quot; data-filename=&quot;스크린샷 2024-05-08 오후 12.24.45.png&quot; data-origin-height=&quot;545&quot; data-origin-width=&quot;1608&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NCY4f/btsHjeBLMP1/ZuSZKTJWpFErqUZDUKCcH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNCY4f%2FbtsHjeBLMP1%2FZuSZKTJWpFErqUZDUKCcH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1608&quot; height=&quot;545&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ACL 활성화 여부는 외부 노출을 원천 봉쇄하기 위함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmJLFn/btsHgpdIQAF/UGxbHrcwKopqyUNbZVPtt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmJLFn/btsHgpdIQAF/UGxbHrcwKopqyUNbZVPtt1/img.png&quot; style=&quot;width: 40.7504%; margin-right: 10px;&quot; data-widthpercent=&quot;41.23&quot; data-filename=&quot;스크린샷 2024-05-08 오후 12.30.08.png&quot; data-origin-height=&quot;1130&quot; data-origin-width=&quot;1638&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmJLFn/btsHgpdIQAF/UGxbHrcwKopqyUNbZVPtt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmJLFn%2FbtsHgpdIQAF%2FUGxbHrcwKopqyUNbZVPtt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1638&quot; height=&quot;1130&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZaUlf/btsHisN1016/ebalTCWmwvI7ooO9itT4TK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZaUlf/btsHisN1016/ebalTCWmwvI7ooO9itT4TK/img.png&quot; style=&quot;width: 58.0868%;&quot; data-widthpercent=&quot;58.77&quot; data-filename=&quot;스크린샷 2024-05-08 오후 12.29.26.png&quot; data-origin-height=&quot;785&quot; data-origin-width=&quot;1622&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZaUlf/btsHisN1016/ebalTCWmwvI7ooO9itT4TK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZaUlf%2FbtsHisN1016%2FebalTCWmwvI7ooO9itT4TK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1622&quot; height=&quot;785&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;버킷 생성 과정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버킷에 대한 접근을 CloudFront에서 할 것이기에 퍼블릭 엑세스 차단&lt;/li&gt;
&lt;li&gt;버킷 버전에 대한 관리 필요성이 없기에 비활성화&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;  S3 버킷 설정&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AWS &amp;gt; S3 &amp;gt; [버킷 네임] &amp;gt; 속성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qzZgP/btsHiby1r9Q/IM0E9cbKfANJV0RZ7x0e4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qzZgP/btsHiby1r9Q/IM0E9cbKfANJV0RZ7x0e4k/img.png&quot; style=&quot;width: 31.7582%; margin-right: 10px;&quot; width=&quot;600&quot; height=&quot;228&quot; data-widthpercent=&quot;32.13&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2768&quot; data-origin-height=&quot;1051&quot; data-filename=&quot;스크린샷 2024-05-08 오후 12.38.14.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qzZgP/btsHiby1r9Q/IM0E9cbKfANJV0RZ7x0e4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqzZgP%2FbtsHiby1r9Q%2FIM0E9cbKfANJV0RZ7x0e4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2768&quot; height=&quot;1051&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5soXj/btsHgprfDlv/s418jZoVBcPujxtTFk3hrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5soXj/btsHgprfDlv/s418jZoVBcPujxtTFk3hrk/img.png&quot; style=&quot;width: 67.079%;&quot; width=&quot;600&quot; height=&quot;108&quot; data-widthpercent=&quot;67.87&quot; data-is-animation=&quot;false&quot; data-filename=&quot;set1.png&quot; data-origin-height=&quot;199&quot; data-origin-width=&quot;1107&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5soXj/btsHgprfDlv/s418jZoVBcPujxtTFk3hrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5soXj%2FbtsHgprfDlv%2Fs418jZoVBcPujxtTFk3hrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1107&quot; height=&quot;199&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정적 웹 사이트 호스팅을 활성화하여 S3 버킷을 웹사이트로 이용&lt;/b&gt;할 수 있게끔 할 수 있다. 이는 S3 버킷에 저장된 파일을 웹 브라우저에서 직접 엑세스할 수 있게 해주기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cG5wZX/btsHgYGXF0P/7gLhZkOwRv84ZZj4kMI3w0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cG5wZX/btsHgYGXF0P/7gLhZkOwRv84ZZj4kMI3w0/img.png&quot; style=&quot;width: 35.0185%; margin-right: 10px;&quot; width=&quot;600&quot; height=&quot;482&quot; data-widthpercent=&quot;35.43&quot; data-is-animation=&quot;false&quot; data-filename=&quot;set2.png&quot; data-origin-height=&quot;669&quot; data-origin-width=&quot;832&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cG5wZX/btsHgYGXF0P/7gLhZkOwRv84ZZj4kMI3w0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcG5wZX%2FbtsHgYGXF0P%2F7gLhZkOwRv84ZZj4kMI3w0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;832&quot; height=&quot;669&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MWISH/btsHf99Zlf2/ZkHzrVBpiB0hUIFVz6Wp30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MWISH/btsHf99Zlf2/ZkHzrVBpiB0hUIFVz6Wp30/img.png&quot; style=&quot;width: 63.8187%;&quot; data-widthpercent=&quot;64.57&quot; data-filename=&quot;스크린샷 2024-05-08 오후 2.07.25.png&quot; data-origin-height=&quot;638&quot; data-origin-width=&quot;1446&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MWISH/btsHf99Zlf2/ZkHzrVBpiB0hUIFVz6Wp30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMWISH%2FbtsHf99Zlf2%2FZkHzrVBpiB0hUIFVz6Wp30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1446&quot; height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설정을 완료하면 버킷 웹 사이트 엔드포인트가 부여가 되지만 정책 설정 및 프로젝트를 올리지 않았기에 접속시 403Error가 발생한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AWS &amp;gt; S3 &amp;gt; [버킷 네임] &amp;gt; 권한&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;s3.console.aws.amazon.com_s3_buckets_kansinbeom-testapp-bucket1_region=ap-northeast-2&amp;amp;amp;amp;tab=permissions (1).png&quot; data-origin-width=&quot;1271&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmkrIv/btsHgZZ8AP3/bV2QKwvycGxMwtlpNqyk2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmkrIv/btsHgZZ8AP3/bV2QKwvycGxMwtlpNqyk2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmkrIv/btsHgZZ8AP3/bV2QKwvycGxMwtlpNqyk2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmkrIv%2FbtsHgZZ8AP3%2FbV2QKwvycGxMwtlpNqyk2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;127&quot; data-filename=&quot;s3.console.aws.amazon.com_s3_buckets_kansinbeom-testapp-bucket1_region=ap-northeast-2&amp;amp;amp;tab=permissions (1).png&quot; data-origin-width=&quot;1271&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버킷 정책 설정을 하기 위해서는 기존에&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;퍼블릭 엑세스 차단을 비활성화&lt;/b&gt;로 바꾼 뒤 진행하면 된다.&lt;/li&gt;
&lt;li&gt;버킷 정책은 버킷을 사용할 권한을 가진 여러 명의 사용자 별로 각각의 행위에 대한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;권한 범위를 설정&lt;/b&gt;하는 것이다. 이를 통해 읽기, 쓰기 등 행동에 대한 제한을 가할 수도 있고 허용할 수도 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정책 생성기&lt;/b&gt;를 통해 간편하게 정책을 생성할 수 있으며 아래와 같은 방식으로 정책을 생성해보자.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;정책 생성&lt;/i&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정책 생성기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4가지를 설정하면 된다&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Select Type of Policy에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;S3 Bucket Policy&lt;/b&gt;를 선택한다.&lt;/li&gt;
&lt;li&gt;Effect는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Allow&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;설정&lt;/li&gt;
&lt;li&gt;Principa은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;*&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;설정&lt;/li&gt;
&lt;li&gt;Action은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;GetObjcet&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;설정&amp;nbsp;&lt;/li&gt;
&lt;li&gt; Amazon Resorce Name에 복사해놓은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ARN에 끝에 /*를 붙인다.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-05-08 오후 2.19.11.png&quot; data-origin-width=&quot;2208&quot; data-origin-height=&quot;1476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7qlK1/btsHgcscbjj/0ogOYCTSjwgxAZJ6hPPWm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7qlK1/btsHgcscbjj/0ogOYCTSjwgxAZJ6hPPWm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7qlK1/btsHgcscbjj/0ogOYCTSjwgxAZJ6hPPWm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7qlK1%2FbtsHgcscbjj%2F0ogOYCTSjwgxAZJ6hPPWm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2208&quot; height=&quot;1476&quot; data-filename=&quot;스크린샷 2024-05-08 오후 2.19.11.png&quot; data-origin-width=&quot;2208&quot; data-origin-height=&quot;1476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 정책 문서는 IAM의 정책으로 사용되어 특정 사용자 또는 그룹, 리소스가 S3 버킷에 대한 어떤 작업을 수행할 수 있는지를 제어하고 일반적으로 다음과 같은 내용을 포함한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;어떤 작업이 허용되는지 (GetObject ...)&lt;/li&gt;
&lt;li&gt;어떤 리소스에 대한 엑세스가 허용되는지 (특정 버킷, 버킷의 모든 객체 ...)&lt;/li&gt;
&lt;li&gt;엑세스를 요청할 수 있는 조건 (IP 주소, IAM 역할 ...)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 정책은 S3 버킷 자체에 직접 연결되지 않고 IAM 사용자, 그룹 또는 역할에 연결되어 AWS의 엑세스 제어 매커니즘을 통해 사용자의 권한을 관리하고 제어할 수 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;  AWS CLI를 통한 S3 버킷에 프로젝트 업로드&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://docs.aws.amazon.com/ko_kr/cli/latest/userguide/getting-started-install.html&quot;&gt; &lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;- Install&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRcXRm/btsHgcZ0b2w/pSEx0gNP1eGnTu20yegaxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRcXRm/btsHgcZ0b2w/pSEx0gNP1eGnTu20yegaxk/img.png&quot; style=&quot;width: 58.8446%; margin-right: 10px;&quot; width=&quot;600&quot; height=&quot;264&quot; data-widthpercent=&quot;59.54&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1630&quot; data-origin-height=&quot;718&quot; data-filename=&quot;스크린샷 2024-05-08 오후 2.36.53.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRcXRm/btsHgcZ0b2w/pSEx0gNP1eGnTu20yegaxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRcXRm%2FbtsHgcZ0b2w%2FpSEx0gNP1eGnTu20yegaxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1630&quot; height=&quot;718&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caim5i/btsHfCdw93E/u9sRsLNVBfs0REXjQcf8p0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caim5i/btsHfCdw93E/u9sRsLNVBfs0REXjQcf8p0/img.png&quot; style=&quot;width: 39.9926%;&quot; data-widthpercent=&quot;40.46&quot; data-filename=&quot;스크린샷 2024-05-08 오후 2.39.42.png&quot; data-origin-height=&quot;781&quot; data-origin-width=&quot;1205&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caim5i/btsHfCdw93E/u9sRsLNVBfs0REXjQcf8p0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcaim5i%2FbtsHfCdw93E%2Fu9sRsLNVBfs0REXjQcf8p0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1205&quot; height=&quot;781&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가이드 내용에 따라 설치 후 aws에 대한 설치 상태를 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- User setting (CLI)&lt;/b&gt;&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;aws configure --profile [IAM 사용자 이름]&lt;br /&gt;Key ID :&amp;nbsp;IAM 사용자 추가할 때 다운받았던 CSV 파일의 Access key ID&lt;br /&gt;Access Key :&amp;nbsp;IAM 사용자 추가할 때 다운받았던 CSV 파일의 Secret access key&lt;br /&gt;region name :&amp;nbsp;ap-northeast-2output&lt;br /&gt;format :&amp;nbsp;json&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Uploading&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715159859376&quot; class=&quot;jboss-cli&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// package.json

{
	...
    &quot;script&quot;: {
    	...
        &quot;deploy&quot;: &quot;aws s3 sync ./dist s3://[S3 버킷 이름] --profile=[IAM 사용자 이름]&quot;
    }
}
// ./dist는 vite를 사용해서 그런거고 CRA를 이용했다면 ./build로 나올 것임&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;✅  CloudFront에 배포하기&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;   CloudFront의 이점?&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;성능&lt;/b&gt;&lt;br /&gt;정적 리소스에 대해 캐시를 사용하여 데이터를 관리할 수 있으며 캐시를 짧게 하거나 날리는 등 적절하게 설정한다면 성능상 많은 개선을 할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안&lt;br /&gt;&lt;/b&gt;CloudFront만을 통해서 유저가 S3로 접근할 수 있어 보안을 높일 수 있다(public Access를 비활성화할 수 있다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;글로벌 서비스&lt;br /&gt;&lt;/b&gt;CloudFront는 생성한 region에 속하지 않고 엣지 로케이션이라는 캐싱 서버에 캐싱되기에 전 세계 사용자들에게 빠르게 응답할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;   &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;CloudFront&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;배포 생성&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AWS &amp;gt;  CloudFront &amp;gt; 배포 &amp;gt; 생성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dXL9Od/btsHiaz6Rpr/AlHT0FqiQzk8mWU9xBIaHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dXL9Od/btsHiaz6Rpr/AlHT0FqiQzk8mWU9xBIaHK/img.png&quot; style=&quot;width: 51.8113%; margin-right: 10px;&quot; data-widthpercent=&quot;52.42&quot; data-filename=&quot;스크린샷 2024-05-08 오후 3.16.20.png&quot; data-origin-height=&quot;986&quot; data-origin-width=&quot;1641&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dXL9Od/btsHiaz6Rpr/AlHT0FqiQzk8mWU9xBIaHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdXL9Od%2FbtsHiaz6Rpr%2FAlHT0FqiQzk8mWU9xBIaHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1641&quot; height=&quot;986&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYUYcu/btsHgWCqFsi/A8IsvkIb1fozdk5Np2nTsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYUYcu/btsHgWCqFsi/A8IsvkIb1fozdk5Np2nTsK/img.png&quot; style=&quot;width: 47.0259%;&quot; data-widthpercent=&quot;47.58&quot; data-filename=&quot;스크린샷 2024-05-08 오후 3.17.10.png&quot; data-origin-height=&quot;1087&quot; data-origin-width=&quot;1642&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYUYcu/btsHgWCqFsi/A8IsvkIb1fozdk5Np2nTsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYUYcu%2FbtsHgWCqFsi%2FA8IsvkIb1fozdk5Np2nTsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1642&quot; height=&quot;1087&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Origin domain에 대해 S3 버킷을 선택한 뒤 버킷을 CloudFront에서만 접근할 수 있게 하기위해 원본 엑세스 설정 후 OAC를 생성하자&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-05-08 오후 3.20.51.png&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lOSb0/btsHfCkluPA/i1326itLRMnPm8tKc2Bs21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lOSb0/btsHfCkluPA/i1326itLRMnPm8tKc2Bs21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lOSb0/btsHfCkluPA/i1326itLRMnPm8tKc2Bs21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlOSb0%2FbtsHfCkluPA%2Fi1326itLRMnPm8tKc2Bs21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;196&quot; data-filename=&quot;스크린샷 2024-05-08 오후 3.20.51.png&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;533&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Origin Shield를 활성화함으로 엣지 로케이션에서 가져오는 콘텐츠의 요청을 최적화할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;  Origin Shield&lt;/i&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Origin Shield의 유무&lt;br /&gt;&lt;br /&gt;여러 지역에 엣지 로케이션이 존재하고 요청하는 객체를 캐시에 가지고 있지 않을 때에는 각 엣지 로케이션이&amp;nbsp; 동시에 Origin으로 요청을해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;S3 버킷에 대해 과부화&lt;/b&gt;가 일어날 수 있다. 이때 Origin Shield가 있다면 요청은 Shield로 가게되고 Origin Shield가 S3 버킷에서 객체를 가져오게 된다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모든 엣지 로케이션은 Shield로 요청을 하므로 S3에 대한 부하를 줄일 수 있고 이를 통해 전번적인 성능과 신뢰성을 향상시킬 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpApn2/btsHgXHYIYJ/UWwuIFyIE6y9lxVYZ4R9wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpApn2/btsHgXHYIYJ/UWwuIFyIE6y9lxVYZ4R9wk/img.png&quot; style=&quot;width: 25.1996%; margin-right: 10px;&quot; data-widthpercent=&quot;25.5&quot; data-filename=&quot;스크린샷 2024-05-08 오후 3.29.21.png&quot; data-origin-height=&quot;1239&quot; data-origin-width=&quot;1638&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpApn2/btsHgXHYIYJ/UWwuIFyIE6y9lxVYZ4R9wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpApn2%2FbtsHgXHYIYJ%2FUWwuIFyIE6y9lxVYZ4R9wk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1638&quot; height=&quot;1239&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m0qkb/btsHh8bfEHx/lW6mfBEASWPO6oprSxzYu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m0qkb/btsHh8bfEHx/lW6mfBEASWPO6oprSxzYu0/img.png&quot; style=&quot;width: 73.6376%;&quot; data-widthpercent=&quot;74.5&quot; data-filename=&quot;스크린샷 2024-05-08 오후 3.29.54.png&quot; data-origin-height=&quot;424&quot; data-origin-width=&quot;1638&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m0qkb/btsHh8bfEHx/lW6mfBEASWPO6oprSxzYu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm0qkb%2FbtsHh8bfEHx%2FlW6mfBEASWPO6oprSxzYu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1638&quot; height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 캐시 동작은 뷰어 프로토콜 정책만 변경 후 나머지는 기본값으로 사용한다.&lt;/li&gt;
&lt;li&gt;WAF는 악의적인 HTTP/S 트래픽을 필터링, 모니터링 및 타단하여 웹 앱을 보호하고, 승인되지 않은 데이터가 앱에서 나가는 것을 방지하지만 비용이 청구되는 옵션이기에 비활성화&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0Ni8w/btsHfCxREHj/0eCvKwaebmLm3YhC4EoxH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0Ni8w/btsHfCxREHj/0eCvKwaebmLm3YhC4EoxH1/img.png&quot; style=&quot;width: 33.3969%; margin-right: 10px;&quot; width=&quot;400&quot; height=&quot;709&quot; data-widthpercent=&quot;33.79&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;1113&quot; data-filename=&quot;cf3.png&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0Ni8w/btsHfCxREHj/0eCvKwaebmLm3YhC4EoxH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0Ni8w%2FbtsHfCxREHj%2F0eCvKwaebmLm3YhC4EoxH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;628&quot; height=&quot;1113&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3vchU/btsHfBeEMoS/De80KEDD4kDCP4uIhjAK50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3vchU/btsHfBeEMoS/De80KEDD4kDCP4uIhjAK50/img.png&quot; style=&quot;width: 65.4403%;&quot; data-is-animation=&quot;false&quot; data-filename=&quot;cf4.png&quot; data-origin-height=&quot;748&quot; data-origin-width=&quot;827&quot; data-widthpercent=&quot;66.21&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3vchU/btsHfBeEMoS/De80KEDD4kDCP4uIhjAK50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3vchU%2FbtsHfBeEMoS%2FDe80KEDD4kDCP4uIhjAK50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;827&quot; height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배포 완료 후 사용자 정의 오류 응답편집을 설정하여 마무리를 하면 된다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;이후&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;CloudFront의 배포 도메인&lt;/b&gt;을 통해서 접근할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;✅  Github Action으로 CI / CD 구축&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;   CI / CD(Continuous Integration / Continuous Deployment)란?&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;지속적 통합&lt;/b&gt;은 개발 팀이 코드를 지속적으로 통합하고 이를 자동으로 테스트하여 버그를 최소화하는 프로세스이다. 코드 변경 시(push)에 자동으로 빌드 및 테스트를 진행하여 프로덕트 품질 관리 및 버그 발견이 빨라질 수 있으며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;지속적 배포&lt;/b&gt;를 통해 새로운 기능을 사용자에게 빠르게 전달하고 구축 시간을 단축시킬 수 있습니다.&amp;nbsp;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;github aciton뿐만아니라 Jenkins, Travis... 여러 CI / CD 툴이 존재한다.&lt;/li&gt;
&lt;li&gt;위와 같은 도구를 통해서 배포에 대한 파이프라인을 설정한다.&lt;/li&gt;
&lt;li&gt;파이프라인 구축을 통해 불필요한 비용도 줄이고, 개발에만 집중할 수 있는 환경을 조성할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;   &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;.github/workflows/cicd&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;.yaml 만들기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-05-08 오후 4.13.39.png&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eyHFtJ/btsHgZFRJER/zFHWVpOlcmSieA8pLcESwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eyHFtJ/btsHgZFRJER/zFHWVpOlcmSieA8pLcESwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eyHFtJ/btsHgZFRJER/zFHWVpOlcmSieA8pLcESwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeyHFtJ%2FbtsHgZFRJER%2FzFHWVpOlcmSieA8pLcESwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;282&quot; data-filename=&quot;스크린샷 2024-05-08 오후 4.13.39.png&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1715159859378&quot; class=&quot;http&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;name: front-dev-deploy

on:
  push:
    branches: main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v3

      - name: Install Dependencies
        run: pnpm

      - name: Build
        run: pnpm run build

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-2

      - name: S3 Deploy
        run: aws s3 sync ./dist s3://${{ secrets.AWS_S3_BUCKET }} --acl bucket-owner-full-control

      - name: Invalidate CloudFront Cache
        run: aws cloudfront create-invalidation --distribution-id ${{secrets.CLOUD_FRONT_ID}} --paths &quot;/*&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;   secret 설정하기&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/jakejarvis/s3-sync-action&quot;&gt; &lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;Build 및 Deploy 환경에 사용될 환경 변수를 등록하는 것으로 각 환경변수가 무슨 값인지 헷갈리지 않도록 주의해야한다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;scr.png&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;1018&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPZJQN/btsHis1zcnX/XeS14MvET1qQ2gBlo1QAE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPZJQN/btsHis1zcnX/XeS14MvET1qQ2gBlo1QAE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPZJQN/btsHis1zcnX/XeS14MvET1qQ2gBlo1QAE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPZJQN%2FbtsHis1zcnX%2FXeS14MvET1qQ2gBlo1QAE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1236&quot; height=&quot;1018&quot; data-filename=&quot;scr.png&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;1018&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://velog.io/@ssongji/AWS-IAM-%EA%B0%9C%EB%85%90-%EA%B8%B0%EB%8A%A5-%EB%B0%8F-IAM-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0&quot;&gt;[AWS] IAM 개념, 기능 및 IAM 사용자 추가하기&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://velog.io/@codns1223/.etc-AWS-S3-Cloudfront-%EB%B0%B0%ED%8F%AC&quot;&gt;AWS-S3-Cloudfront-배포&lt;/a&gt;&amp;nbsp; &amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://velog.io/@doohyunlm/AWS-S3-%EB%B2%84%ED%82%B7-%EA%B6%8C%ED%95%9C-%EC%84%A4%EC%A0%95&quot;&gt;S3 버킷 권한 설정&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://voyage-dev.tistory.com/164&quot;&gt;[AWS] 정적 웹 페이지 배포하기 (S3 + CloudFront)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://velog.io/@sangwoong/CICD-GitHub-Action%EC%9C%BC%EB%A1%9C-CICD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0&quot;&gt;CICD GitHub Action으로 CICD 구축하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>CS</category>
      <author>고래강이</author>
      <guid isPermaLink="true">https://together-cs.tistory.com/119</guid>
      <comments>https://together-cs.tistory.com/119#entry119comment</comments>
      <pubDate>Wed, 8 May 2024 18:17:55 +0900</pubDate>
    </item>
  </channel>
</rss>