<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>byeoung.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Mon, 13 Jan 2025 13:20:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>byeoung.log</title>
            <url>https://velog.velcdn.com/images/chan-byeong/profile/4bf6ca94-b7dc-4c20-8c08-57ad308d530e/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. byeoung.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/chan-byeong" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[React] 스켈레톤 UI를 잘 작성해보자.]]></title>
            <link>https://velog.io/@chan-byeong/React-%EC%8A%A4%EC%BC%88%EB%A0%88%ED%86%A4-UI%EB%A5%BC-%EC%9E%98-%EC%9E%91%EC%84%B1%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@chan-byeong/React-%EC%8A%A4%EC%BC%88%EB%A0%88%ED%86%A4-UI%EB%A5%BC-%EC%9E%98-%EC%9E%91%EC%84%B1%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Mon, 13 Jan 2025 13:20:45 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>웹 애플리케이션에서 데이터 로딩은 불가피한 요소이다. 이러한 상황에서 스켈레톤 UI는 사용자 경험을 크게 개선할 수 있는 중요한 디자인 패턴이다.</p>
<h3 id="현재의-문제점">현재의 문제점</h3>
<p>현재 애플리케이션은 모든 페이지에서 동일한 로딩 컴포넌트를 사용하고 있다. 이는 다음과 같은 한계를 가지고 있다.</p>
<ul>
<li>사용자가 로드될 콘텐츠의 구조를 예측할 수 없음</li>
<li>페이지별 특성을 반영하지 못하는 획일적인 로딩 표시</li>
<li>콘텐츠 로드 완료 시 갑작스러운 레이아웃 변화</li>
</ul>
<h3 id="스켈레톤-ui를-통한-개선">스켈레톤 UI를 통한 개선</h3>
<p>스켈레톤 UI는 실제 콘텐츠가 표시될 영역의 구조를 미리 보여주는 방식이다. 이는 마치 건물의 뼈대를 먼저 세우는 것과 같은 원리로, 다음과 같은 이점을 제공한다.</p>
<ul>
<li>페이지의 최종 레이아웃을 미리 파악 가능</li>
<li>더 자연스러운 로딩 경험 제공</li>
<li>사용자의 체감 로딩 시간 감소</li>
</ul>
<h2 id="어떤-기준으로-컴포넌트를-수정할까">어떤 기준으로 컴포넌트를 수정할까?</h2>
<p>위에서 언급한대로 스켈레톤 UI는 뼈대를 보여주는 UI이다.</p>
<p>따라서 <strong>뼈대가 되는 컴포넌트</strong>들을 외부 컴포넌트로 따로 제작하고 Props를 활용하여 스켈레톤 UI인지 실제로 컨텐츠를 보여주는 UI인지 구분하려고 한다.</p>
<h3 id="뼈대-컴포넌트-분리하기">뼈대 컴포넌트 분리하기</h3>
<p><img src="https://velog.velcdn.com/images/chan-byeong/post/c232f52b-eb2d-4b7b-9f8a-f8dce7c0be7a/image.png" alt=""></p>
<p>위 화면의 스켈레톤을 제작한다면 그림처럼 뼈대를 잡을 수 있을 것이다.</p>
<p>가장 큰 뼈대는 <code>ClassItem</code> 이라는 컴포넌트로 이미 분리되어 있다. 그렇다면 <code>ClassItem</code> 컴포넌트의 Props를 추가하여 스켈레톤일 때와 아닐 때의 UI를 바꿔주면 될 것 같다.</p>
<h3 id="문제점">문제점</h3>
<p>위의 방식대로 구현을 하던 중 문제점을 발견했다.</p>
<p>우선 <code>ClassItem</code>의 기존 Props는 아래와 같다.</p>
<pre><code class="language-jsx">interface ClassItemProps {
  quizList: Quiz;
  index: number;
}</code></pre>
<p>변경된 Props는 아래와 같다.</p>
<pre><code class="language-jsx">interface ClassItemProps {
  varient: &#39;skeleton&#39; | &#39;content&#39;;
  quizList?: Quiz;
  index?: number;
}</code></pre>
<p>문제점은 바로 <code>quizList?</code> 에서 나타난다.</p>
<p>optional props이기 때문에 <code>quizList</code>의 타입은 <code>Quiz | undefined</code>로 잡히게 되어 <code>quizList</code>를 활용하는 부분에서 타입에러가 발생한다.</p>
<h3 id="해결책">해결책</h3>
<p>위 문제의 해결책으로 <code>Union</code> 타입과 타입 단언을 사용했다.</p>
<p>이게 최선의 해결책인지는 모르겠으나 위와 같은 방식을 활용하기 위한 임시 해결책이다.</p>
<p>방법은 아래와 같다.</p>
<pre><code class="language-jsx">interface SkeletonProps {
  varient: &#39;skeleton&#39;;
}
interface ContentProps {
  varient: &#39;content&#39;;
  quizList: Quiz;
  index: number;
}

type ClassItemProps = SkeletonProps | ContentProps;

export default function ClassItem(props: ClassItemProps) {

    ...

  if (props.varient === &#39;skeleton&#39;) {
       ...
  }

  const { quizList, index } = props as ContentProps;</code></pre>
<p>스켈레톤 Props와 컨텐츠 Props를 분리하여 Union 타입으로 지정 후 조건문을 통해 해당 되는 props에 접근한다.</p>
<h3 id="결과">결과</h3>
<p>props를 통해 스켈레톤 UI를 제작한 방식의 장점을 꼽아보자면,</p>
<ul>
<li><p>컴포넌트 재활용성이 올라갔다.</p>
<ul>
<li><code>varient</code> props를 추가하여 스켈레톤일 때와 아닐 때 다른 UI를 리턴해주는 방식으로 <code>ClassItem</code> 컴포넌트를 재활용할 수 있었다.</li>
</ul>
</li>
<li><p>SkeletonUI의 코드가 간단하다.</p>
<pre><code class="language-jsx">  export default function SkeletonQuizList() {
    return (
      &lt;div className=&quot;w-full min-h-[calc(100vh-80px)] px-8 flex flex-col gap-6 mt-6 mx-auto&quot;&gt;
        &lt;ClassItem varient=&quot;skeleton&quot; /&gt;
      &lt;/div&gt;
    );
  }</code></pre>
<p>  단순히 <code>varient</code> props만을 추가한 컴포넌트를 사용하기 때문에 간단한 구조를 가진다.</p>
</li>
</ul>
<p>반면 위 방식의 단점을 꼽아보면,</p>
<ul>
<li><code>ClassItem</code>의 복잡도가 올라갔다.<ul>
<li>기존 오롯이 <code>ClassItem</code>에만 쓰이는 비지니스 로직과 UI 코드가 존재했다면, <code>varient</code> props를 추가해줌으로써 <code>varient</code> 를 판단하는 로직과 스켈레톤 UI 코드가 혼재하면서 코드가 복잡해졌다.</li>
</ul>
</li>
<li>다소 난해한 Props 타입<ul>
<li>이전에는 Props를 Union 타입으로 활용해본적이 없어서 난해하게 느껴질지 모르겠으나, Props를 Union타입으로 선언하면서 불필요한 타입단언이 생겼다.</li>
</ul>
</li>
</ul>
<p>위의 장단점을 저울질 해보았을 때 개인적인 생각으로는 단점이 더 크다고 생각한다.</p>
<p>가장 큰 단점은 <code>ClassItem</code> 컴포넌트의 복잡도가 올라간 것이다.</p>
<p>사실 스켈레톤 컴포넌트는 단순한 UI만 제공하면 되기 때문에 현재 <code>ClassItem</code>에 존재하는 코드를 스켈레톤 컴포넌트에 넣는다고해서 코드의 복잡도가 크지는 않다.</p>
<p>하지만 <code>ClassItem</code> 컴포넌트는 실제 컨텐츠와 관련된 비지니스 로직과 UI들이 존재하기 때문에 스켈레톤과 관련된 코드들이 존재하면 다소 혼란스러울 수 있다.</p>
<h2 id="결론">결론</h2>
<p>위에서 언급한 Props를 활용한 방식은 장점보다 단점이 크다고 생각한다.</p>
<p>그래서 스켈레톤 컴포넌트에 스켈레톤 UI를 직접 작성하는 방법으로 코드를 짰다.</p>
<p>기본적인 레이아웃만을 보여주기 때문에 직접 코드를 작성해도 매우 길이가 매우 짧고 간결했다.</p>
<p>위의 UI는 간단한 구조이기 때문에 직접 스켈레톤 UI를 작성하는 방식이 더 알맞다고 생각한다.</p>
<p>그렇다면 좀 더 복잡한 구조에서 스켈레톤 UI를 작성해보자.</p>
<h2 id="복잡한-ui의-스켈레톤">복잡한 UI의 스켈레톤</h2>
<p>결론부터 말하면 복잡한 UI의 스켈레톤은 더더욱 Props 방식을 지양해야된다는 것을 느꼈다.</p>
<p>기본적으로 UI가 복잡한 만큼 컴포넌트 내부의 비지니스 로직과 Props도 많아서 여기에 <code>Varient</code> Props를 추가하여 스켈레톤 UI를 추가하면 더욱 복잡해졌다.</p>
<p>그렇다면 좀 더 슬기롭게 스켈레톤 UI를 작성하는 방법은 무엇일까 생각해보다가 <code>MUI</code>의 스켈레톤 컴포넌트를 참고했다.</p>
<h3 id="mui의-스켈레톤">MUI의 스켈레톤</h3>
<p>MUI는 <code>&lt;Skeleton /&gt;</code> 이라는 컴포넌트가 존재한다. </p>
<p>해당 컴포넌트의 props로 모양, 크기, 애니메이션 등을 지정하여 사용한다.</p>
<p>즉, 회색 컴포넌트가 미리 생성되어 있고 props로 회색 컴포넌트를 조정한다고 생각하면된다.</p>
<pre><code class="language-jsx">&lt;Skeleton variant=&quot;circular&quot; width={40} height={40} /&gt;  // 원형
&lt;Skeleton variant=&quot;rectangular&quot; width={210} height={60} /&gt;  // 사각형
&lt;Skeleton variant=&quot;rounded&quot; width={210} height={60} /&gt;  // 둥근 모서리</code></pre>
<p>MUI의 스켈레톤 컴포넌트를 참고해서 기존의 복잡한 스켈레톤 UI를 수정해보았다.
결과는 아래와 같다.</p>
<ul>
<li>위에서 언급한 복잡한 컴포넌트 스켈레톤<ul>
<li>컴포넌트 구조가 매우 복잡하여 읽기가 힘들다.</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">export default function SkeletonQuizWait() {
  return (
    &lt;div className=&quot;flex justify-center gap-4 pt-8&quot;&gt;
      &lt;div className=&quot;flex flex-col gap-6 justify-center items-center&quot;&gt;
        &lt;div className=&quot;w-full bg-white rounded-xl shadow-md p-6&quot;&gt;
          &lt;div className=&quot;relative flex items-center justify-between mb-4 gap-2&quot;&gt;
            &lt;div className=&quot;flex items-center gap-2&quot;&gt;
              &lt;div className=&quot;h-10 w-32 bg-gray-100 rounded-xl animate-pulse&quot; /&gt;
              &lt;div className=&quot;h-10 w-32 bg-gray-200 rounded-xl animate-pulse&quot; /&gt;
            &lt;/div&gt;
            &lt;div className=&quot;absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-64 h-6 bg-gray-100 rounded-md animate-pulse&quot; /&gt;
            &lt;div className=&quot;flex items-center gap-6&quot;&gt;
              &lt;div className=&quot;h-10 w-24 bg-gray-100 rounded-2xl animate-pulse&quot; /&gt;
              &lt;div className=&quot;h-10 w-32 bg-gray-100 rounded-md animate-pulse&quot; /&gt;
            &lt;/div&gt;
          &lt;/div&gt;

          &lt;div className=&quot;w-full bg-gray-50 rounded-xl shadow-md&quot;&gt;
            &lt;div className=&quot;grid grid-cols-8 gap-16 p-8&quot;&gt;
              {Array.from({ length: 32 }).map((_, index) =&gt; (
                &lt;div key={index} className=&quot;flex flex-col items-center animate-pulse&quot;&gt;
                  &lt;div className=&quot;w-20 h-20 bg-gray-200 rounded-full&quot; /&gt;
                  &lt;div className=&quot;w-16 h-4 bg-gray-200 rounded-md mt-2&quot; /&gt;
                &lt;/div&gt;
              ))}
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;div className=&quot;relative flex justify-end min-w-full&quot;&gt;
          &lt;div className=&quot;h-10 w-32 bg-gray-200 rounded-xl animate-pulse&quot; /&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre>
<ul>
<li><code>&lt;Skeleton /&gt;</code> 컴포넌트를 적용한 모습<ul>
<li>스켈레톤 컴포넌트에는 기본 배경 색과 애니메이션 코드만 작성되어있다.</li>
<li>여전히 복잡하나 약간은 정돈된 느낌이 든다.</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">    &lt;div className=&quot;flex justify-center gap-4 pt-8&quot;&gt;
      &lt;div className=&quot;flex flex-col gap-6 justify-center items-center&quot;&gt;
        &lt;div className=&quot;w-full bg-white rounded-xl shadow-md p-6&quot;&gt;
          &lt;div className=&quot;relative flex items-center justify-between mb-4 gap-2&quot;&gt;
            &lt;div className=&quot;flex items-center gap-2&quot;&gt;
              &lt;Skeleton className=&quot;h-10 w-32 rounded-xl&quot; /&gt;
              &lt;Skeleton className=&quot;h-10 w-32 rounded-xl&quot; /&gt;
            &lt;/div&gt;
            &lt;div className=&quot;absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-64 h-6 bg-gray-100 rounded-md animate-pulse&quot; /&gt;
            &lt;div className=&quot;flex items-center gap-6&quot;&gt;
              &lt;Skeleton className=&quot;h-10 w-24 rounded-2xl&quot; /&gt;
              &lt;Skeleton className=&quot;h-10 w-32 rounded-md&quot; /&gt;
            &lt;/div&gt;
          &lt;/div&gt;

          &lt;div className=&quot;w-full bg-gray-50 rounded-xl shadow-md&quot;&gt;
            &lt;div className=&quot;grid grid-cols-8 gap-16 p-8&quot;&gt;
              {Array.from({ length: 32 }).map((_, index) =&gt; (
                &lt;div key={index} className=&quot;flex flex-col items-center animate-pulse&quot;&gt;
                  &lt;Skeleton className=&quot;w-20 h-20 rounded-full&quot; /&gt;
                  &lt;Skeleton className=&quot;w-16 h-4 bg-gray-200 rounded-md mt-2&quot; /&gt;
                &lt;/div&gt;
              ))}
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;div className=&quot;relative flex justify-end min-w-full&quot;&gt;
          &lt;Skeleton className=&quot;h-10 w-32 rounded-xl&quot; /&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;</code></pre>
<ul>
<li>레이아웃을 커스텀 컴포넌트로 분리하고 스켈레톤을 적용한 모습<ul>
<li>컴포넌트명 덕분에 읽기는 훨씬 수월하다.</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">&lt;QuizWaitLayout&gt;
    &lt;QuizWaitHeader&gt;
        &lt;div className=&quot;w-full bg-white rounded-xl shadow-md p-6&quot;&gt;
          &lt;div className=&quot;relative flex items-center justify-between mb-4 gap-2&quot;&gt;
            &lt;div className=&quot;flex items-center gap-2&quot;&gt;
              &lt;Skeleton className=&quot;h-10 w-32 rounded-xl&quot; /&gt;
              &lt;Skeleton className=&quot;h-10 w-32 rounded-xl&quot; /&gt;
            &lt;/div&gt;
            &lt;div className=&quot;absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-64 h-6 bg-gray-100 rounded-md animate-pulse&quot; /&gt;
            &lt;div className=&quot;flex items-center gap-6&quot;&gt;
              &lt;Skeleton className=&quot;h-10 w-24 rounded-2xl&quot; /&gt;
              &lt;Skeleton className=&quot;h-10 w-32 rounded-md&quot; /&gt;
            &lt;/div&gt;
          &lt;/div&gt;
    &lt;/QuizWaitHeader&gt;
    &lt;QuizWaitBoard&gt;
         &lt;div className=&quot;grid grid-cols-8 gap-16 p-8&quot;&gt;
            {Array.from({ length: 32 }).map((_, index) =&gt; (
              &lt;div key={index} className=&quot;flex flex-col items-center animate-pulse&quot;&gt;
                &lt;Skeleton className=&quot;w-20 h-20 rounded-full&quot; /&gt;
                &lt;Skeleton className=&quot;w-16 h-4 bg-gray-200 rounded-md mt-2&quot; /&gt;
              &lt;/div&gt;
            ))}
          &lt;/div&gt;
      &lt;/div&gt;
    &lt;/QuizWaitBoard&gt;
    &lt;div className=&quot;relative flex justify-end min-w-full&quot;&gt;
    &lt;Skeleton className=&quot;h-10 w-32 rounded-xl&quot; /&gt;
  &lt;/div&gt;
&lt;/QuizWaitLayout&gt;</code></pre>
<ul>
<li>최종 컴포넌트 코드<ul>
<li>초기 컴포넌트 로직 작성 시 레이아웃 컴포넌트들을 잘 분리하고,</li>
<li>내부 요소에 대한 스타일들을 클래스로 분리하여 작성하면 아래와 같은 모습이다.</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">&lt;QuizWaitLayout&gt;
    &lt;QuizWaitHeader&gt;
        &lt;div className=&quot;w-full bg-white rounded-xl shadow-md p-6&quot;&gt;
          &lt;div className=&quot;relative flex items-center justify-between mb-4 gap-2&quot;&gt;
            &lt;div className=&quot;flex items-center gap-2&quot;&gt;
              &lt;Skeleton className=&quot;wait-header-button&quot; /&gt;
              &lt;Skeleton className=&quot;wait-header-pincode&quot; /&gt;
            &lt;/div&gt;
            &lt;div className=&quot;absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-64 h-6 bg-gray-100 rounded-md animate-pulse&quot; /&gt;
            &lt;div className=&quot;flex items-center gap-6&quot;&gt;
              &lt;Skeleton className=&quot;wait-header-participants&quot; /&gt;
              &lt;Skeleton className=&quot;wait-header-number&quot; /&gt;
            &lt;/div&gt;
          &lt;/div&gt;
    &lt;/QuizWaitHeader&gt;
    &lt;QuizWaitBoard&gt;
         &lt;div className=&quot;grid grid-cols-8 gap-16 p-8&quot;&gt;
            {Array.from({ length: 32 }).map((_, index) =&gt; (
              &lt;div key={index} className=&quot;flex flex-col items-center animate-pulse&quot;&gt;
                &lt;Skeleton className=&quot;wait-board-character&quot; /&gt;
                &lt;Skeleton className=&quot;wait-board-nickname&quot; /&gt;
              &lt;/div&gt;
            ))}
          &lt;/div&gt;
      &lt;/div&gt;
    &lt;/QuizWaitBoard&gt;
    &lt;div className=&quot;relative flex justify-end min-w-full&quot;&gt;
    &lt;Skeleton className=&quot;wait-footer-button&quot; /&gt;
  &lt;/div&gt;
&lt;/QuizWaitLayout&gt;</code></pre>
<h2 id="최종-결론">최종 결론</h2>
<p>스켈레톤 UI를 잘 작성하기 위해서 필요한 것은 다음과 같다는 결론을 내렸다.</p>
<ul>
<li>분리된 레이아웃 컴포넌트</li>
<li>내부 요소에 대한 스타일 클래스화</li>
<li>커스텀 스켈레톤 컴포넌트 활용</li>
</ul>
<p>초기에 스켈레톤을 고려하지 않고 코드를 작성하다보니 프로젝트가 마무리되고 이를 수정하려니 시간과 노력이 많이 들었다. </p>
<p>이번 경험을 통해서 스켈레톤 뿐 아니라 재사용성이 높은 컴포넌트 제작에 필요한 기본적인 요소들을 습득할 수 있었다고 생각한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Socket.io와 Tanstack Query 함께 쓰기]]></title>
            <link>https://velog.io/@chan-byeong/Socket.io%EC%99%80-Tanstack-Query-%ED%95%A8%EA%BB%98-%EC%93%B0%EA%B8%B0</link>
            <guid>https://velog.io/@chan-byeong/Socket.io%EC%99%80-Tanstack-Query-%ED%95%A8%EA%BB%98-%EC%93%B0%EA%B8%B0</guid>
            <pubDate>Wed, 01 Jan 2025 10:16:54 GMT</pubDate>
            <description><![CDATA[<h2 id="socker-server-state-관리-전략">Socker Server State 관리 전략</h2>
<p>현재 프로젝트는 실시간 양방향 통신을 위해 소켓을 활용하고 있으며, 대부분의 데이터가 소켓을 통해 주고받는 형태다. 기존에는 API를 통해 서버 데이터를 수신하고 이를 <strong>React-Query</strong>로 관리하려 했으나, API 호출이 적어 소켓 기반 데이터 관리로 방향을 전환했다. 따라서 소켓 통신으로 받는 <strong>Server State</strong>를 React-Query로 브라우저 캐시에서 관리하는 방안을 고민하게 되었다.</p>
<h3 id="브라우저-캐시에-저장할-데이터의-기준">브라우저 캐시에 저장할 데이터의 기준</h3>
<p>소켓을 통해 전달되는 모든 데이터를 브라우저 캐시에 저장하는 것은 비효율적이다. 예를 들어, 채팅과 같은 자주 변동되는 데이터는 캐시할 필요가 없다. 반면, <strong>퀴즈 상태</strong>, <strong>참가자 정보</strong>와 같은 준영속적이고 중요한 데이터는 캐시 관리에 포함하는 것이 바람직하다</p>
<h3 id="react-query와-socket의-효율적-통합-usesuspensequery와-emiteventwithack-활용">React-Query와 Socket의 효율적 통합: <code>useSuspenseQuery</code>와 <code>emitEventWithAck</code> 활용</h3>
<p>소켓 데이터를 관리할 때 <strong>React-Query</strong>와 <strong>useSuspenseQuery</strong>를 결합하면, 소켓 기반 데이터 흐름에서도 브라우저 캐시와 상태 관리를 효율적으로 수행할 수 있다. 기존의 <code>useState</code> 대신 <strong>React-Query</strong>의 캐시를 활용하여, 새로고침 시 자동으로 데이터를 패치할 수 있는 구조를 제공한다. 이를 위해<strong>emitEventWithAck</strong> 함수를 사용하여 소켓 이벤트를 Promise 기반으로 처리한다.</p>
<p><code>emitEventWithAck</code>: 소켓 이벤트의 Promise 래핑</p>
<pre><code class="language-jsx">import { Socket } from &#39;socket.io-client&#39;;

export const emitEventWithAck = &lt;T&gt;(socket: Socket, event: string, data: any) =&gt; {
  return new Promise&lt;T&gt;((resolve, reject) =&gt; {
    socket.emit(event, data, (response: T) =&gt; {
      if (response) {
        resolve(response);
      } else {
        reject(new Error(`&quot;${event}&quot; event emit failed`));
      }
    });
  });
};
</code></pre>
<p><code>useQuizSession</code>: React-Query와 소켓 데이터 통합</p>
<p>이 훅은 <code>useSuspenseQuery</code>를 사용하여 소켓 데이터를 React-Query의 캐시에서 관리한다. 이를 통해 <strong>퀴즈 세션</strong> 데이터를 브라우저에서 자동으로 캐싱하며, 새로고침 시에도 데이터를 자동으로 불러올 수 있는 구조를 제공한다.</p>
<pre><code class="language-jsx">//예시 코드
export const useQuizSession = ({ socket, pinCode }: UseQuizSessionProps) =&gt; {
  return useSuspenseQuery({
    queryKey: [&#39;show quiz&#39;, pinCode],
    queryFn: () =&gt; emitEventWithAck&lt;ShowQuizResponse&gt;(socket, &#39;show quiz&#39;, { pinCode }),
  });
};</code></pre>
<h3 id="사용-사례-및-장점">사용 사례 및 장점</h3>
<ul>
<li><strong><code>useState</code> 불필요</strong>: 소켓 데이터를 관리하는 데 <code>useState</code> 대신 React-Query의 캐시를 사용하여 코드가 간결해진다.</li>
<li><strong>응답 대기 처리</strong>: <code>emitEventWithAck</code>를 통해 소켓 이벤트 응답을 Promise로 관리하여 비동기 처리와 에러 핸들링이 용이하다.</li>
<li><strong>효율적인 캐시 관리</strong>: React-Query의 <code>queryKey</code>를 활용해 필요한 데이터만 갱신하고 불필요한 요청을 줄인다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[부스트캠프 멤버십] 6주차 회고]]></title>
            <link>https://velog.io/@chan-byeong/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%A4%EB%B2%84%EC%8B%AD-6%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@chan-byeong/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%A4%EB%B2%84%EC%8B%AD-6%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 06 Oct 2024 12:24:53 GMT</pubDate>
            <description><![CDATA[<p>5주차 회고를 작성하지 않았다.
지난 2주간의 학습 스프린트를 회고해본다.</p>
<h3 id="지난-2주에-대한-평가">지난 2주에 대한 평가</h3>
<p>챌린지와 멤버십 과정을 통틀어서 가장 학습과 구현을 못한 시간이었다. 그 원인에 대해서 생각해보면 1주간 인터미션으로 쉬고 그 다음주에 4일 동안 예비군을 갔다오면서 너무 오래 쉰 탓에 그런 것 같다. 그 전까지 이어오던 공부 템포를 잃어버린 느낌이다. 그래서인지 집중도 안되고 게임을 좀 했다. </p>
<p>다행히도 좋은 팀원분들과 멘토님을 만나서 갈수록 회복이 되는 것을 느꼈다. 너무 열심히 해주시고 챙겨주셔서 이 분들에게 폐를 끼치면 안되겠다는 생각으로 따라갔다. 그래서 후반부에는 템포를 다시 찾은 느낌이다.</p>
<h3 id="반성할-점">반성할 점</h3>
<p>이번 학습 스프린트는 목표없이 주변 눈치만 살피며 나아갔다. 피어세션이나 그룹세션 때 어떻게는 결과물을 들고가야된다는 생각에 &quot;학습&quot; 스프린트의 의미가 무색하게 나를 위한 학습 과정이 빠져있었다. 그래서 절대적인 시간 투자도 부족한 것이 있지만 지난 2주간 알맹이 없는 시간을 보낸 것 같다. </p>
<h3 id="개선방향">개선방향</h3>
<p>목표 설정의 중요성을 느꼈다. 그래서 다음 2주가 시작되기 전에는 나의 목표를 정하고 시작하려고 한다. 이번 목표 중 하나는 팀원 분들에게 긍정적인 영향을 끼치겠다는 굉장히 어려운 목표도 있다. 이번 학습 스프린트에서 내가 도움을 받았던 것처럼 나도 남들에게 도움을 주고 싶다. 남에게 긍정적인 영향을 끼치는 가장 쉬운 방법은 굉~장히 열심히 하는 것이라 생각한다. </p>
<h3 id="화이팅">화이팅!</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[[부스트캠프 멤버십] 4주차 회고]]></title>
            <link>https://velog.io/@chan-byeong/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%A4%EB%B2%84%EC%8B%AD-4%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@chan-byeong/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%A4%EB%B2%84%EC%8B%AD-4%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 15 Sep 2024 10:04:26 GMT</pubDate>
            <description><![CDATA[<p>4주가 끝나고 연휴다...마지막 한주는 매우 아쉬운 한 주 였다. 그치만 쉬니까 좋다 </p>
<h2 id="한줄평">한줄평</h2>
<p>지난주보다 퇴행한 한 주</p>
<h2 id="이번주의-나">이번주의 나</h2>
<p>3주차에는 리팩토링에 집중한 한 주 였다면, 4주차에는 남은 기능에 집중하려고 했으나!@!@!
4일 중 하루는 거의 날렸다. 가장 큰 원인은 도망간 집중력이다. 체력이 문제일까 아니면 그냥 마음가짐의 문제일까. 아침에 일어나는 게 힘들고 과제에 집중이 힘들었다. 그래서 멍때리거나 유튜브 보는 시간이 길어지고 기능 구현에 많이 힘을 쓰지 못했다. 그리고 4일 중 하루는 유튜브보다가 3D 멀미 이슈로 1시간 정도 앓아누웠다. </p>
<h2 id="지난-주와-바뀐-점">지난 주와 바뀐 점</h2>
<p>지난 주는 계획을 한대로 착실히 보낸 한 주 였지만 이번주는 아무것도 지키지 못 한 한 주 이다. 우선 화,목에는 운동을 가기로 했으나 운동을 가지 않았고, 학습한 내용을 블로그에 포스팅 하기로 했으나 하나도 하지 않았다. 그 때문에 학습은 했으나 깊이있는 학습을 하지 않았다. </p>
<p>대체로 부정적인 한 주 였으나, 배운점도 있다. 그룹원 분들을 보면서 기술적인 부분이나 태도적인 부분을 보며 나를 반성하였다. 반성으로 끝나면 되지 않고 이를 실천해야한다. 다행히도 한 주는 쉬어갈 수 있다. 이때 어떤 부분을 어떻게 개선해야할 지 곰곰이 생각해봐야겠다. </p>
<h2 id="정리">정리</h2>
<p>천금같은 한 주. 야무지게 잘 활용하자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[부스트캠프 멤버십] 3주차 회고]]></title>
            <link>https://velog.io/@chan-byeong/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%A4%EB%B2%84%EC%8B%AD-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@chan-byeong/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%A4%EB%B2%84%EC%8B%AD-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 08 Sep 2024 11:31:58 GMT</pubDate>
            <description><![CDATA[<p>시간이 빠르다 벌써 3주가 끝나고 한달차가 되어간다.</p>
<h2 id="한줄평">한줄평</h2>
<p>지난주보다 발전된 한 주</p>
<p><img src="https://velog.velcdn.com/images/chan-byeong/post/51a505d7-9d38-40cc-837f-d1142203a788/image.png" alt=""></p>
<h2 id="이번주의-나">이번주의 나</h2>
<p>1,2주차 보다 구현보단 학습과 코드 개선에 집중한 한 주 였다.
기능구현은 좀 늦춰줬지만 더 단단하게 다지고 나아간다는 느낌을 받아서 지난 주보다 만족감이 높은 한 주였다. 이러한 방식으로 앞으로 학습 스프린트를 보낼 생각이다. 기능 구현이 늦어지는 것은 시간을 좀 더 할애하여 개선할 생각이다.</p>
<h2 id="지난-주와-바뀐-점">지난 주와 바뀐 점</h2>
<ul>
<li>학습한 내용을 정리하여 블로그 포스팅을 하였다.</li>
<li>구현한 코드를 리팩토링하는데 시간을 할애했다.</li>
</ul>
<h2 id="다음주의-나">다음주의 나</h2>
<p>학습과 구현의 비중을 6:4 정도로 다시 조정할 생각이다. 지난 주는 7:3의 비율이었다고 생각한다. 지난주는 리팩토링에 상당한 시간을 할애했는데 코드 구현 시 &quot;리팩토링하면 되지&quot;라는 생각을 버리고 구현할 때부터 깔끔한 코드를 작성해야겠다. 이번에 &quot;Tidy First?&quot;라는 책을 구매했는데 책에서 제시하는 방법대로 작은 것부터 깔끔한 코드로 작성해나갈 생각이다.</p>
<p>그리고 기록에 대한 고민이 많았는데 노션을 활용하며 좀 더 체계화된 기록을 할 수 있었다. 하지만 다른 캠퍼 분들을 보면 아직은 한참 부족한데 다른 분들이 어떻게 하는지 참고해나가면서 기록의 체계화도 더 발전시킬 계획이다.</p>
<h2 id="정리">정리</h2>
<p>학습-기록-구현-리팩토링 병렬로 처리하자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Express에서 미들웨어를 활용한 에러처리하기]]></title>
            <link>https://velog.io/@chan-byeong/Express%EC%97%90%EC%84%9C-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%97%90%EB%9F%AC%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@chan-byeong/Express%EC%97%90%EC%84%9C-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%97%90%EB%9F%AC%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 05 Sep 2024 13:29:59 GMT</pubDate>
            <description><![CDATA[<h3 id="미들웨어란">미들웨어란?</h3>
<p>요청과 응답 중간에 존재하여 미들웨어라 부른다.
미들웨어는 요청과 응답을 조작하여 기능을 추가하기도 하고, 잘못된 요청을 걸러내는 역할도 한다.</p>
<p>Express에서는 웹 요청과 응답에 대한 정보를 사용해서 필요한 처리를 진행할 수 있도록 분리된 독립적인 <strong>함수</strong>이다.</p>
<h3 id="미들웨어-종류">미들웨어 종류</h3>
<h4 id="1-어플리케이션-레벨-미들웨어">1. 어플리케이션 레벨 미들웨어</h4>
<p><code>app.use(미들웨어 함수)</code> 또는 <code>app.METHOD(미들웨어 함수)</code>
( <code>METHOD</code>: <code>get, post, delete ...</code> )
내에서 정의되는 미들웨어를 의미한다.</p>
<h4 id="2-라우터-레벨-미들웨어">2. 라우터 레벨 미들웨어</h4>
<p>Express의 <code>Router</code> 객체에 bind된 미들웨어를 의미한다.</p>
<pre><code class="language-javascript">const router = express.Router();

router.get(&#39;/&#39;,(req, res) =&gt; { ... });

app.use(&#39;/api&#39;, router);</code></pre>
<p><code>/api</code>로 들어오는 요청에 대해서 등록된 미들웨어 함수가 동작한다.</p>
<h4 id="3-빌트인-미들웨어">3. 빌트인 미들웨어</h4>
<p>Express에 내장된 미들웨어 함수를 의미한다.</p>
<h4 id="4-서드파티-미들웨어">4. 서드파티 미들웨어</h4>
<p>서드파티 라이브러리에서 제공하는 미들웨어를 사용하여 기능을 추가할 수 있다.</p>
<h4 id="5-에러-핸들링-미들웨어">5. 에러 핸들링 미들웨어</h4>
<p>에러가 발생했을 때 호출되는 미들웨어이다.
일반미들웨어는 3개의 인자를 기본적으로 받지만 에러 핸들링 미들웨어는 <strong>4개의 인자를 받는다.</strong></p>
<pre><code class="language-javascript">app.use((err, res, req, next) =&gt; {
  ...
}) </code></pre>
<h4 id="에러-핸들링-미들웨어가-호출되는-경우">에러 핸들링 미들웨어가 호출되는 경우</h4>
<ul>
<li><p><strong>동기 처리 시 발생한 에러</strong>
  동기 처리 시 발생한 에러는 <code>try - catch</code>문에서 throw Error를 할 경우 Express가 해당 에러를 잡아 에러 핸들링 미들웨어를 호출시킨다.<br/></p>
<p>  하지만 더 일반적인 방법은 <code>next(err)</code>를 통해서 에러 핸들링 미들웨어를 호출해주는 것이 더 명시적이기 때문에 <code>next(err)</code> 표현을 활용하는 것이 더 좋다.</p>
</li>
</ul>
<ul>
<li><strong>비동기 처리 시 발생한 에러</strong>
비동기 처리 시 발생한 에러는 동기 처리 시 발생한 에러와는 다르게 <code>throw Error</code>를 통해 발생한 에러를 Express가 잡아주지 못한다. 
그래서 이때는 명시적으로 <code>next(err)</code>를 통해서 에러 핸들링 미들웨어를 호출해주어야 한다.</li>
</ul>
<h3 id="미들웨어-추가-방법">미들웨어 추가 방법</h3>
<h4 id="1-전역-미들웨어">1. 전역 미들웨어</h4>
<blockquote>
<p>모든 요청에 대해서 실행되는 미들웨어이다.</p>
</blockquote>
<p><code>app.use(미들웨어 함수)</code>를 활용하여 전역 미들웨어를 추가할 수 있다.
서버에 요청이 들어오면 항상 미들웨어 함수가 실행된다.</p>
<h4 id="2-특정-경로에-대한-미들웨어">2. 특정 경로에 대한 미들웨어</h4>
<blockquote>
<p>특정 경로로 들어온 요청에 대해서만 미들웨어가 실행되도록 한다.</p>
</blockquote>
<pre><code class="language-javascript">app.use(&#39;/api&#39; , (req, res) =&gt; { ... })</code></pre>
<p><code>app.use()</code>의 첫번째 인자로 경로를 지정하여 특정 경로에 대해서만 미들웨어가 실행되도록 할 수 있다.</p>
<h4 id="3-여러-개의-미들웨어-등록">3. 여러 개의 미들웨어 등록</h4>
<p>미들웨어 함수는 하나만이 아니라 여러개 등록할 수 있다.</p>
<pre><code class="language-javascript">app.use( (req, res) =&gt; { ...1... } , (req, res) =&gt; { ...2... })</code></pre>
<p>단, 이때 순차적으로 미들웨어 함수가 실행되게 하기위해서는 <strong><code>next()</code> 함수를 반드시 호출해야 한다.</strong>
위의 경우 <code>...1...</code> 만 실행되고 다음 미들웨어 함수는 실행되지 않는다.</p>
<pre><code class="language-javascript">app.use( (res, res, next) =&gt; { ...1... next() } ,
        (req, res) =&gt; { ...2... })</code></pre>
<p>위의 경우 처럼 앞선 미들웨어 함수에서 <code>next()</code>를 호출해야 다음 미들웨어 함수가 실행이 된다.</p>
<h3 id="미들웨어-함수">미들웨어 함수</h3>
<ul>
<li><p>기본 인자 : req , res , next , err (에러 핸들링 미들웨어)</p>
</li>
<li><p>인자의 역할 :
req : request 객체 , 요청에 대한 정보를 담고 있다.
res : response 객체 , 이를 통해 서버에서 클라이언트로 데이터를 전송하거나, 상태 코드를 설정하고, 응답 본문을 정의할 수 있다.
next : 미들웨어 흐름 제어 , next(err) 시 에러 핸들링 미들웨어로 넘어간다.
err : 에러 핸들링 미들웨어에서 사용되며 에러에 대한 정보를 담고 있다.</p>
</li>
<li><p>2개 이상 미들웨어 함수를 등록할 수 있다.</p>
</li>
</ul>
<h2 id="express에서-에러-핸들링-하기">Express에서 에러 핸들링 하기!</h2>
<h3 id="현재-be-구조">현재 BE 구조</h3>
<p><img src="https://velog.velcdn.com/images/chan-byeong/post/3b3ad425-caec-438f-9528-c9da095468bc/image.png" alt=""></p>
<h3 id="현재-문제점">현재 문제점</h3>
<ol>
<li><p>반복된 try-catch 사용</p>
<p> service, controller의 모든 함수에서 try-catch문을 사용하고 있다.</p>
</li>
<li><p>구체화되지 않은 Error code</p>
<p> 대부분의 에러들이 500 에러로 구체화되어 있지 않다.</p>
</li>
<li><p>Error handle Middleware의 미사용</p>
<p> Error handle Middleware가 구현이 되어있으나 이를 활용하지 않고 있다.</p>
</li>
</ol>
<h3 id="문제-해결-방법">문제 해결 방법</h3>
<ol>
<li><p>반복된 try-catch문 =&gt; Wrapper 함수 활용</p>
<p> 각 service, controller 함수들을 감싸는 wrapper함수를 만들어 두고 wrapper 함수 내에서 try-catch 문을 통해 에러 핸들링을 수행하였다.</p>
<p> 반복되어 사용하던 try-catch문을 줄일 수 있었다.</p>
</li>
<li><p>구체화되지 않은 Error code =&gt; custom Error class 선언 및 활용</p>
<p> Error 클래스를 extends 하는 커스텀 에러 클래스를 선언해두고 예상되는 에러 사항에 맞는 에러 클래스들을 호출하여 에러를 세분화하여 관리하였다.</p>
</li>
<li><p>Error handle Middleware 활용</p>
<p> Controller 함수들을 감싸는 Wrapper함수에서 에러 발생 시 next(error)를 통해 에러 핸들링 미들웨어로 에러를 보내도록 하여 해당 미들웨어에서 에러 처리를 하도록 수행하였다.</p>
</li>
</ol>
<p>[참고자료]:
<a href="https://inpa.tistory.com/entry/EXPRESS-%F0%9F%93%9A-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-%F0%9F%92%AF-%EC%9D%B4%ED%95%B4-%EC%A0%95%EB%A6%AC">[EXPRESS] 📚 미들웨어 이론 &amp; 실용 💯 정리</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS는 어떻게 동작할까]]></title>
            <link>https://velog.io/@chan-byeong/NodeJs%EB%A5%BC-Araboza</link>
            <guid>https://velog.io/@chan-byeong/NodeJs%EB%A5%BC-Araboza</guid>
            <pubDate>Wed, 04 Sep 2024 09:39:12 GMT</pubDate>
            <description><![CDATA[<h2 id="nodejs는-무엇인가">NodeJs는 무엇인가?</h2>
<p>Javascript를 브라우저 외부에서 실행가능하도록 하는 <strong>JS 런타임 환경</strong></p>
<p><em>기존에는 브라우저에서만 동작하여 클라이언트 측 언어였으나 NODEJS 출현 이후 서버에서도 활용된다.</em></p>
<h4 id="런타임-환경">런타임 환경?</h4>
<blockquote>
<p>코드 실행 환경. 즉, 코드를 실행하기 위한 일련의 구성요소와 도구를 의미한다.
크롬 브라우저는 V8 엔진, DOM, Web Apis 등으로 런타임 환경이 구성된다.
NODEJS는 V8엔진, libUV, Nodejs core lib 등으로 런타임 환경이 구성된다.</p>
</blockquote>
<h2 id="nodejs의-특징">NodeJs의 특징</h2>
<ol>
<li>비동기 I/O 및 이벤트 기반 처리 </li>
<li>단일 스레드 모델</li>
<li>이벤트 루프</li>
</ol>
<p>NodeJs는 위와 같은 3가지 특징을 가지는데 위 3가지 특징은 연관성을 가진다.
이를 한 줄로 요약하면 다음과 같다.</p>
<blockquote>
<p>NodeJs는 싱글스레드 기반으로, 비동기 I/O와 이벤트 루프를 통해 논블로킹 처리를 지원하는 런타임 환경이다.</p>
</blockquote>
<p>싱글스레드는 단 하나의 콜스택을 가진다. 즉, 한번에 하나의 일을 처리할 수 있다.
싱글스레드인데 어떻게 비동기적으로 I/O를 처리하는지 의문이 든다.</p>
<h2 id="브라우저에서-js는-어떻게-동작하는가">브라우저에서 JS는 어떻게 동작하는가</h2>
<p>V8 엔진이 Js 런타임 환경을 제공한다.</p>
<h4 id="blocking-이란-무엇인가">Blocking 이란 무엇인가</h4>
<blockquote>
<p>블로킹은 느린 작업을 의미한다. 
콜스택에 느린 작업이 포함된 경우 블로킹이라 말할 수 있다.</p>
</blockquote>
<p>만약 동기적으로 작업한다면 블로킹 코드가 있는 경우 매우 느리게 작업을 수행할 것이다.</p>
<pre><code>console.log(&quot;HI&quot;)
setTimeout(()=&gt;{console.log(&quot;LONG&quot;)},10000)
console.log(&quot;HELLO&quot;)
</code></pre><p>위 코드를 동기적으로 실행하게 된다면 다음과 같이 출력된다.</p>
<pre><code>HI
(10초 뒤)
LONG
HELLO</code></pre><p>하지만 위 코드를 크롬에서 돌리게 되면 다음과 같다.</p>
<pre><code>HI
HELLO
(10초 뒤)
LONG</code></pre><h4 id="어떻게-이런식으로-동작할까">어떻게 이런식으로 동작할까?</h4>
<p>보통 싱글스레드라고 한다면 아래 그림처럼 생각할 수 있다.
<img src="https://velog.velcdn.com/images/chan-byeong/post/c59ba43f-5c2d-4d34-8e23-11523200f5ec/image.png" alt="">
브라우저가 그림과 같다면 위에서 보았던 첫번째 결과처럼 동작할 것이다.
하지만 실제 브라우저는 두번째 결과를 보인다. 
그렇다면 실제 브라우저는 어떻게 동작할까?
<img src="https://velog.velcdn.com/images/chan-byeong/post/944468e4-265c-43ff-baf6-353e24c7bdab/image.png" alt="">
단순히 콜스택과 힙만 있던 구조에서 뭔가가 추가되었다. 딱봐도 중요해보이는 친구들이다.
<code>Web APIs</code> , <code>Queue</code>, <code>EventLoop</code> 이 3가지 덕분에 <strong>브라우저</strong>는 블로킹 코드들을 논 블로킹하게 처리할 수 있게되었다.</p>
<p>세 친구들이 어떻게 동작하는지 알아보자</p>
<p>우선 Web APIs는 setTimeout 같은 타이머의 시간초를 대신 세어주는 친구를 가지고 있다. 그래서 callstack에 들어온 setTimeout의 작업을 Web API에게 떠넘길 수 있다.</p>
<p>Web API는 시간을 세고있다가 정해진 시간이 되면 가지고 있던 callback 함수를 queue에 넣는다.</p>
<p><strong>EventLoop</strong>는 Queue에 존재하는 작업을 Callstack에 집어넣는 역할을 수행하는데 Callstack이 비어있을 경우 작업을 집어넣는다.
Loop라는 말처럼 계속 돌면서 Callstack과 Queue의 상태를 살핀다.</p>
<h3 id="webapis">WebAPIs</h3>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/API">https://developer.mozilla.org/en-US/docs/Web/API</a>
WebAPIs를 찾아볼 수 있다. 
하지만 Timer API는 찾아볼 수 없는데 <code>setTimeout</code>이나 <code>setInterval</code>같은 함수들은 <code>Web Workers API</code>가 하는 기능에서 찾아볼 수 있다.</p>
<h3 id="queue">Queue</h3>
<p>위의 그림에서는 큐 하나로 표현했지만 실제 브라우저에서는 3개의 큐를 가지고 있다.
<code>Task Queue</code> , <code>MicroTask Queue</code> , <code>Render Queue</code>를 가지고 있다.
큐마다 하는 일이 달라서 &#39;큐를 3개로 나누어 놓았겠구나&#39; 라는 생각이든다.</p>
<p>각각의 큐는 어떤 일들을 처리하고 큐 간의 우선순위는 어떻게 나뉘어질까?</p>
<ol>
<li>MicroTask Queue : <ul>
<li>Promise가 성공 또는 실패한 뒤 호출되는 <code>then</code> <code>catch</code>의 콜백함수 들이 들어간다.</li>
<li>MutationObserver의 콜백 함수</li>
<li><code>queueMicrotask()</code>의 콜백함수 </li>
</ul>
</li>
</ol>
<ol start="2">
<li>Task Queue : <ul>
<li>MicroTask가 하지 않는 비동기 작업들이 Task Queue에 들어간다고 생각하면 된다. </li>
</ul>
</li>
</ol>
<ol start="3">
<li>Render Queue : <ul>
<li>브라우저가 화면을 업데이트하고 <code>Repaint</code> 또는 <code>Reflow</code>를 처리할 때 사용되는 큐이다.</li>
<li>DOM, CSS 변경 사항이 있을 경우 해당 작업들을 처리한다.</li>
</ul>
</li>
</ol>
<p>우선순위</p>
<p>Microtask Queue &gt; Task Queue &gt; Render Queue</p>
<h2 id="nodejs는-어떻게-브라우저처럼-동작하게-할까">NodeJS는 어떻게 브라우저처럼 동작하게 할까?</h2>
<p>앞서서 브라우저에서 JS가 동작하는 방식을 보았다.
브라우저에서는 WebAPIs, 큐, 이벤트 루프를 통해서 논블로킹 비동기 처리를 지원할 수 있었다.</p>
<p>NodeJs도 브라우저와 유사한 방법으로 동작한다.
브라우저 환경이 아니기 때문에 WebAPI가 없는 대신 <code>libuv</code>를 활용해서 이를 지원한다.</p>
<p><code>libuv</code> 내부에 이벤트 루프를 가지고 있어 비동기 작업, 네트워크 I/O와 같은 작업들이 이벤트 루프에 의해 처리된다.</p>
<p>하지만 브라우저의 이벤트 루프와는 약간은 다른 점이 <code>libuv</code>의 이벤트 루프는 6 단계를 거친다.</p>
<p><img src="https://velog.velcdn.com/images/chan-byeong/post/85b4d714-66a6-411f-a34a-0e707b851432/image.png" alt="https://www.korecmblog.com/blog/node-js-event-loop">
[출처] <a href="https://www.korecmblog.com/blog/node-js-event-loop">https://www.korecmblog.com/blog/node-js-event-loop</a></p>
<p>6단계의 페이즈 별로 어떻게 동작하는 지
<a href="https://www.korecmblog.com/blog/node-js-event-loop">https://www.korecmblog.com/blog/node-js-event-loop</a> 블로그에 상세하게 나와있으니 참고하시길...</p>
<p>[참고자료]
<a href="https://www.youtube.com/watch?v=P9csgxBgaZ8">https://www.youtube.com/watch?v=P9csgxBgaZ8</a>
<a href="https://sjh836.tistory.com/149">https://sjh836.tistory.com/149</a>
<a href="https://www.korecmblog.com/blog/node-js-event-loop">https://www.korecmblog.com/blog/node-js-event-loop</a>
<a href="https://blog.naver.com/pjt3591oo/221976414901">https://blog.naver.com/pjt3591oo/221976414901</a>
<a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ">https://www.youtube.com/watch?v=8aGhZQkoFbQ</a>
<a href="https://www.youtube.com/watch?v=cCOL7MC4Pl0">https://www.youtube.com/watch?v=cCOL7MC4Pl0</a>
<a href="https://developer.mozilla.org/en-US/docs/Web/API">https://developer.mozilla.org/en-US/docs/Web/API</a>
<a href="https://www.youtube.com/watch?v=eiC58R16hb8">https://www.youtube.com/watch?v=eiC58R16hb8</a>
<a href="https://javascript.plainenglish.io/how-the-event-loop-works-in-the-chrome-browser-ccf99c6c5a5">https://javascript.plainenglish.io/how-the-event-loop-works-in-the-chrome-browser-ccf99c6c5a5</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[부스트캠프 멤버십] 2주차 회고]]></title>
            <link>https://velog.io/@chan-byeong/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%A4%EB%B2%84%EC%8B%AD-1%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@chan-byeong/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%A4%EB%B2%84%EC%8B%AD-1%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 01 Sep 2024 12:58:30 GMT</pubDate>
            <description><![CDATA[<p>챌린지 과정을 끝내고 멤버십에 합류할 수 있었다. 강력해진 내가 멤버십 과정을 어떻게 헤쳐나갈까를 기대하며 멤버십에서의 한 주를 보냈다.</p>
<h2 id="한줄평">한줄평</h2>
<p>한 달 전의 나로 회귀했다... </p>
<h2 id="이번-주의-나">이번 주의 나</h2>
<p>챌린지 초반과 비슷하게 구현과 학습의 균형을 못 잡고 있다.
차라리 학습에 균형이 쏠렸으면 좋았을텐데 구현에 균형이 쏠려 학습이 소홀했다.
구현 진행도는 빠른편이나 나에게 남은 것이 별로 없는 느낌이 강하다.</p>
<p>이를 보완하기 위해 한가지 주제에 대해서 깊게 파면서 공부하고 이를 블로그에 포스팅하기로 했다.
이번주 딥다이브 주제는 NODEJS였고 이를 아직도 공부 중이다...
단순히 공부하는 것은 괜찮지만 이를 글로 남기는 것이 굉장히 어렵다고 느껴진다.</p>
<h2 id="다음-주의-나">다음 주의 나</h2>
<p>이번 주에서 가장 아쉬운 점은 딥다이브한 주제를 포스팅하지 못 한 것이다.
우선 NODEJS를 깊게 공부하고 다음은 브라우저 동작방식에 대해서 깊게 공부해 볼 생각이다.
블로그 포스팅이라는 것에 압박을 갖지 말고 부담없이 작성하고 이를 계속해서 수정해나가야겠다.</p>
<p>두번째로 아쉬운 점은 생활습관이다. 아침 일찍 일어나는 것과 운동하는 습관이 아직 안 잡혀있다.
원래의 목표는 8시 30분에 기상하고 주 3회 운동을 하는 것이 목표였는데 이번 주는 보통 9시에 일어나고 운동은 한번 갔다. 이것도 마찬가지로 부담을 지우고 해야겠다.
8시 30분에 일어나서 바로 뭐를 하지 않아도 일단은 일어나는 것부터, 운동도 무조건 1시간 이상을 하지 않더라도 일단 헬스장에 가는 것부터 하려고 한다.</p>
<h2 id="정리">정리</h2>
<p>부담갖지 말고 가벼운 마음으로 실행을 하자.</p>
]]></description>
        </item>
    </channel>
</rss>