<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ssg-js.log</title>
        <link>https://velog.io/</link>
        <description>헤맨 만큼 내 땅이다</description>
        <lastBuildDate>Tue, 05 Aug 2025 14:19:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ssg-js.log</title>
            <url>https://velog.velcdn.com/images/ssg-js/profile/c5b7cdf9-63a8-4fd0-9fb0-736172333f61/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ssg-js.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ssg-js" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[상경]]></title>
            <link>https://velog.io/@ssg-js/%EC%83%81%EA%B2%BD</link>
            <guid>https://velog.io/@ssg-js/%EC%83%81%EA%B2%BD</guid>
            <pubDate>Tue, 05 Aug 2025 14:19:33 GMT</pubDate>
            <description><![CDATA[<p>드디어 취직했다....!!!!!!!
개발 직무가 아니지만 좋은 기회라 생각해 바로 갔다.
그래서 일단 지금까지 했던 계획들을 모두 없애고 일단 수습 기간을 잘 보내려고 한다.</p>
<h3 id="나쁜-점">나쁜 점</h3>
<p>없다.
개발 시간이 줄어든다고 생각할 수 있는데, 솔직히 돈을 못벌고 있다는 스트레스에 비하면 이제는 오히려 홀가분하게 개발할 수 있다.</p>
<h3 id="좋은-점">좋은 점</h3>
<p>그렇다.
홀가분하다.
커리어는 못 쌓지만, 지금까지 준비해왔던 개발자라는 직업이 너무 매력적이라서 이걸 아예 놓지는 못할 것 같다. 그래서 이제는 진짜 하고 싶은 프로젝트를 할 것이다. 정말 사소하게 쓸모 없어 보이는 것도 재미로 만들어보면서 힐링(?)하려고 한다.</p>
<h3 id="바람">바람</h3>
<p>취업에 목메다보니 개발에 흥미를 잃고 있었는데, 이제는 데이터나 통계, css 애니메이션 위주로 공부하면서 그냥 그저 재밌게 공부하고 싶다. 개발자 친구들과 꾸준히 교류하며 3년 안에는 원하는 직무로 이직할 수 있으면 좋겠다. 잃어버린 흥미와 재미를 찾길 바라며 글을 마친다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[돌아온 회고 시간]]></title>
            <link>https://velog.io/@ssg-js/%EB%8F%8C%EC%95%84%EC%98%A8-%ED%9A%8C%EA%B3%A0-%EC%8B%9C%EA%B0%84</link>
            <guid>https://velog.io/@ssg-js/%EB%8F%8C%EC%95%84%EC%98%A8-%ED%9A%8C%EA%B3%A0-%EC%8B%9C%EA%B0%84</guid>
            <pubDate>Mon, 21 Jul 2025 06:50:40 GMT</pubDate>
            <description><![CDATA[<p>반성이 시간이 돌아왔다.
일주일만에 하겠다고 했지만 이런저런 핑계를 대다가 2주만에 회고를 한다.</p>
<h3 id="이전-계획의-문제점">이전 계획의 문제점</h3>
<p>2주 전에 회고를 하면서 꼭 해야할 일을 하루에 정해진 시간동안 하도록 계획했다.
하지만 시간을 지키다보니 문제가 너무 많이 발생했다.</p>
<ol>
<li>약속이나 면접 일정으로 인해 계획을 지키지 못하는 시간이 늘어난다.</li>
<li>어떤 일을 특정 시간안에 끝내지 못하는 경우 다음 일에 영향을 준다.</li>
<li>어떤 일을 하기 위해 시간을 정했는데 시간을 채우는 것에만 집중하게 된다.</li>
<li>위의 모든 과정들로 인해 하나의 성공보다 더 많은 실패가 발생한다. 이는 동기부여를 흐리게 한다.</li>
<li>글의 내용을 처음부터 바텀업으로 완벽하게 담지 말자. 글을 쓰다보면 당연히 더 공부할 내용과 개념이 생기고 이를 다 커버할 수는 없다. 이는 추후에 수정하거나 다른 글로 보완하자.<h3 id="새로운-계획">새로운 계획</h3>
그래서 이번에는 <strong>x기간 동안 y업무를 z개 하겠다</strong>는 형식으로 계획을 짜려고 한다. (이렇게 적고보니 예전에 JIRA로 이슈를 관리하는 형태랑 비슷하다.)
대신 특정 기간 동안 어떤 업무를 처리하겠다는 &quot;무조건&quot; 지켜야한다. (이 일정은 노션에 따로 관리하거나 시간이 있다면 나에게 맞춘 서비스를 제작해보는 것도 좋을 것 같다.)<h3 id="현재-집중할-것">현재 집중할 것</h3>
2주 전과 비슷하지만 몇 가지 확실해진 부분이 있어서 집중할 일을 다시 짚어보자.</li>
<li>지원하는 회사에 맞게 이력서 수정하고 <strong>매일 3개 이상 지원</strong>해서 면접 기회 가지기</li>
<li>완벽하진 않지만 <strong>이틀에 한번</strong> 블로그 출간하기. 어려운 내용은 개념을 쪼개거나, 좀 더 난이도가 낮은 개념 공부하기</li>
<li>큰 프로덕트가 아닌 정말 작은 하나의 <strong>기능 위주로 개발</strong>하기.</li>
<li>동료들과 진행하는 <strong>사이드 프로젝트 목업을 이번주 안에 완성</strong>하기<h3 id="마무리">마무리</h3>
면접도 떨어지고 여러가지 안 좋은 상황이라 열정을 잃긴 했다. 하지만 &quot;성공과 실패&quot;라는 말보다는 &quot;성공과 과정&quot;이라는 말을 되새기며, 그냥 하자.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[미루다 미루다 하는 회고]]></title>
            <link>https://velog.io/@ssg-js/%EB%AF%B8%EB%A3%A8%EB%8B%A4-%EB%AF%B8%EB%A3%A8%EB%8B%A4-%ED%95%98%EB%8A%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@ssg-js/%EB%AF%B8%EB%A3%A8%EB%8B%A4-%EB%AF%B8%EB%A3%A8%EB%8B%A4-%ED%95%98%EB%8A%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 07 Jul 2025 14:35:16 GMT</pubDate>
            <description><![CDATA[<p>역시 회고의 시작은 반성이다.
한 달 전에 매주 회고를 하겠다는 다짐이 무색하게 이제야 회고한다.
일단 반성할 점을 적어봤다.</p>
<h3 id="반성">반성</h3>
<ol>
<li>회고를 하지 않아서 나쁜 점을 고치지 않고 유지했다.</li>
<li>하루에 해야 할 일을 정하지 않아서 하루가 흐지부지 흘러갔다.</li>
<li>공부한 내용에 대해 블로그에 출간하는 시간을 충분히 가지지 못했다. 그래서 깊이 공부하지 못한 개념이 너무 많다.</li>
</ol>
<h3 id="유지할-점">유지할 점</h3>
<ol>
<li>클론 코딩을 시작하면서 공부할 내용을 많이 확보했다.</li>
<li>매일 회사에 지원하기 시작하면서 그날 공부에 대한 동기부여가 됐다. </li>
</ol>
<h3 id="일주일-동안-지킬-것">일주일 동안 지킬 것</h3>
<p>반성할 점을 고치고 유지할 점을 지키면서, 해야 할 일을 명확히 짚고 적용할 것이다.
현재 집중해야 할 부분은 크게 3가지다.</p>
<ol>
<li>포트폴리오 사이트 만들기</li>
<li>부족한 프론트엔드 공부하기</li>
<li>경쟁력 있는 이력서 작성</li>
</ol>
<p>이를 효율적으로 달성하기 위해서는 매일 시간을 분배해야 한다.
그래서 <strong>오전 9시부터 10시</strong>까지는 <strong>회사에 지원</strong>하면서, <strong>이력서를 수정하고 주변 지인들한테 평가받아</strong>야 한다. 부끄럽지만 좀 더 많이 부끄러워야 원하는 걸 이룰 수 있을 것 같다.
그리고 <strong>10시부터 12시</strong>까지는 <strong>포트폴리오 사이트를 개발</strong>한다. 개발 기간을 일주일로 정하고 세부 일정은 내일 아침에 정해보자.
점심을 먹고 <strong>1시부터 4시</strong>까지는 <strong>블로그에 한 가지 주제로 글을 출간</strong>한다. 이때, 모르는 개념이 계속 생길테지만, 최대한 3시간 안에 마무리하는 것을 목표로 진행한다.
그리고 남은 시간은 <strong>포트폴리오 사이트 개발</strong>, <strong>React Native 공부</strong>, <strong>TypeScript 공부</strong>를 자유롭게 진행한다. (현재 계획에서 개발 비중이 높지 않아서, 일단 이렇게 유동적으로 실행해보려고 한다)</p>
<p>작심삼일도 3일마다 하면 습관이 된다고 했다. 위의 계획을 제발 지키고 일요일에 회고해 보겠다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Controllered & Uncontrolled Component]]></title>
            <link>https://velog.io/@ssg-js/%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Controllered-Component-Uncontrolled-Component</link>
            <guid>https://velog.io/@ssg-js/%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Controllered-Component-Uncontrolled-Component</guid>
            <pubDate>Wed, 25 Jun 2025 06:28:51 GMT</pubDate>
            <description><![CDATA[<p>React를 공부하면서 컴포넌트만 만들줄 알았지, 컴포넌트 패턴이 있는지 몰랐다. 그래서 이번 기회에 제어(controlled) 컴포넌트와 비제어(uncontrolled) 컴포넌트와 추가로 관련된 개념에 대해서 공부해봤다.</p>
<p>참고로 이 개념은 React 18버전 공식문서에 다루는 내용이다.</p>
<h3 id="제어">제어??</h3>
<p>제어라는 말을 들으니 컴포넌트에 어딘가에 의존되어있다는 생각이 먼저 들었다. 상위 컴포넌트가 하위 컴포넌트에 영향을 준다는 것을 단어에서 언뜻 느낄 수 있다.</p>
<h3 id="신뢰할-수-있는-단일-출처a-single-source-of-truth">신뢰할 수 있는 단일 출처(A single source of truth)</h3>
<p>제어 &amp; 비제어 컴포넌트를 설명하기에 앞서, 이 개념부터 설명해야 한다. 리액트에서는 컴포넌트마다 정말 다양한 상태를 가진다. 그래서 이 각각의 고유한 상태를 어떤 컴포넌트가 “소유”할지 정할 수 있다. 이 원칙은 “신뢰할 수 있는 단일 출처”를 가진다고도 말할 수 있다. </p>
<blockquote>
<p><strong>신뢰할 수 있는 단일 출처(A single source of truth)</strong>
정보시스템 설계 및 이론에서, 관련된 모든 데이터 요소를 한 곳에서만 제어 또는 편집하도록 조직하는 관례를 말한다. 이는 데이터 복제본이 존재할 때 원본 데이터가 수정된다면, 복제본과 이를 조회하는 모든 작업에서 잘못된 이전 데이터를 조회하는 위험성이 생긴다. 그렇기 때문에 항상 원본 데이터를 조회하게 설계해야 한다. (출처: <a href="https://ko.wikipedia.org/wiki/%EB%8B%A8%EC%9D%BC_%EC%A7%84%EC%8B%A4_%EA%B3%B5%EA%B8%89%EC%9B%90">Wikipedia 단일 진실 공급원</a></p>
</blockquote>
<p>이를 통해 컴포넌트마다 중복된 상태를 가지게 하는 것이 아니라, 공통 부모로 상태를 끌어올리고, 이를 필요한 자식에게 전달하게 설계할 수 있다. </p>
<h3 id="form-element-먼저-이해하기">Form Element 먼저 이해하기</h3>
<p>form element는 자체적으로 내부 상태(입력 값, 대표적으로 input value)를 가지기 때문에 React의 다른 DOM element와 다르게 동작한다. 사용자의 입력을 받는 방식은 input, textarea, select(여기서는 해당 태그의 속성까지는 다루지 않겠다)가 있다. 그리고 이 태그로 입력받는 값을 <strong>React에 의해 값을 제어하는 방법</strong>과 <strong>기존처럼 DOM에 직접 접근해서 값을 제어하는 방식</strong>이 존재한다. </p>
<h3 id="제어-컴포넌트controlled-component">제어 컴포넌트(Controlled Component)</h3>
<p>제어 컴포넌트는 리액트의 상태(state)를 통해 입력 값을 제어하는 컴포넌트를 말한다. 그래서 입력값(value)을 리액트 상태와 동기화하고, 사용자가 입력할 때마다 onChange 이벤트 핸들러를 통해 상태를 업데이트한다. </p>
<p>그래서, 제어 컴포넌트는 입력 값을 상태로 관리하기 때문에, 입력 할 때마다 값을 검증하거나, 값을 자유롭게 변경할 수 있으며, 복잡한 폼 로직을 처리하는 데 유용하다.</p>
<p>단, 입력 값을 상태로 관리하기 때문에 입력 값이 변경 될 때마다 리렌더링이 발생한다.</p>
<p>아래에 코드를 보며 이해해보자.</p>
<pre><code class="language-jsx">// 제어 컴포넌트 예시 코드
function ControlledComponent() {
  const [value, setValue] = useState(&quot;&quot;);

  return &lt;input type=&quot;text&quot; value={value} onChange={(e)=&gt;setValue(e.target.value)} /&gt;;
}</code></pre>
<p>이 코드는 보다시피 input 태그의 value 속성을 상태로 관리하고 있다. </p>
<p>여기서 주의할 점은 onChange 이벤트 핸들러로 input 태그의 이벤트를 감지해 사용자가 입력한 값으로 상태를 갱신해줘야 한다는 것이다. 이렇게 상태를 갱신하지 않으면 입력 값을 상태에 전달하지 못해 화면에서도 보이지 않고, 실제 상태도 빈 상태가 된다.</p>
<h3 id="비제어-컴포넌트uncontrolled-component">비제어 컴포넌트(Uncontrolled Component)</h3>
<p>비제어 컴포넌트는 입력 값을 리액트의 상태로 관리하지 않고, DOM을 통해 입력 값을 제어하는 방식이다. 그래서 입력 값은 DOM에서 직접 관리되고, 리액트는 이에 관여하지 않는다. 그래서 useRef 훅을 사용해 참조 객체인 ref를 사용해 입력 태그의 DOM 요소에 직접 접근해서 값을 읽거나 조작한다.</p>
<p>그래서, 비제어 컴포넌트는 리액트 상태 관리에 따른 성능 비용(리렌더링)이 없다. </p>
<p>하지만 입력 값을 동적으로 할당하는 등의 조작을 불가능해서 보통 간단한 폼에서 사용한다.</p>
<p>예시로 아래 코드를 보자.</p>
<pre><code class="language-jsx">// 비제어 컴포넌트 예시 코드
function UncontrolledComponent() {
  const ref = useRef(&#39;&#39;);

  const handleSubmit = (e) =&gt; {
    e.preventDefault(); // 해당 이벤트에 대해 기본적으로 구현된 동작을 정지시킴.

    console.log(ret.current.value); // 출력: (사용자 입력값)
  }

  return (
    &lt;form onSubmit={() =&gt; {}}&gt;
      &lt;input type=&#39;text&#39; ref={ref} /&gt;
    &lt;/form&gt;
  );
}</code></pre>
<p>위 코드에서는 input 태그의 DOM 요소를 ref 객체로 받는다. ref.current는 DOM 요소를 가리키게 되고, 최종적으로 value 값에 접근할 수 있다.</p>
<p>여기서 입력 값은 React 상태로 제어되지 않고 DOM 요소에 의해 알아서 변경된다. </p>
<h3 id="유효성-검사">유효성 검사</h3>
<p>비제어 컴포넌트의 경우 submit 이벤트 발생 시 유효성 검사를 실행한다. 그래서 유저가 즉각적인 입력에 대한 피드백을 받을 수 없다. 위의 비제어 컴포넌트 예시 코드를 보면 ref는 값의 변경이 일어나도 리렌더링이 일어나지 않기 때문에 어떤 피드백을 화면에 띄워 유저에게 알려줄 수 없다. </p>
<p>하지만, 제어 컴포넌트의 경우 입력 값이 바뀔 때마다 유효성 검사를 실시해 유저에게 즉각적인 피드백을 줄수 있다. 입력 값에 따라 상태가 변경되어 리렌더링이 발생하기 때문에 이 상태를 가지고 유효성 검사를 실시한 결과를 화면에 바로 띄울 수 있다. </p>
<h3 id="react-19버전에서의-제어-컴포넌트와-비제어-컴포넌트">React 19버전에서의 제어 컴포넌트와 비제어 컴포넌트</h3>
<p>React 19버전 공식문서에 따르면, 지역 상태만으로 중요한 로직을 처리하는 컴포넌트를 <strong>“비제어 컴포넌트”</strong>라고 부른다. 말 그대로 비제어 컴포넌트는 부모 컴포넌트에서 “제어할 수 없는” 컴포넌트를 가리킨다. </p>
<blockquote>
<p><strong>지역 상태(Local State)</strong>
props를 통해 만들어지는 상태가 아닌 컴포넌트 자체에서 생성되는 상태를 일컫는다.</p>
</blockquote>
<p>반대로, <strong>“제어 컴포넌트”</strong>는 부모 컴포넌트에서 “제어할 수 있는” 컴포넌트다. 대표적인 예로 props를 통해 상태를 전달해 컴포넌트의 중요한 상태에 영향을 주는 경우가 있다.</p>
<p>설명에서 느껴지는 바와 같이, React 19버전 공식문서에서는 제어 &amp; 비제어 컴포넌트가 엄격한 기술 용어가 아니다. 하지만 이런 구분을 통해 <strong>컴포넌트의 설계를 명확히하고 설명하는 데 유용한 방법</strong>이라고 소개되어 있다. </p>
<p>이는 18버전에서 form element에만 적용되는 제어 &amp; 비제어 개념을 전체 컴포넌트로 확장한 것 같다.</p>
<h3 id="마무리">마무리</h3>
<p>오늘은 입력을 처리하는 컴포넌트 패턴을 이해하고 18버전에서와 19버전에서 어떻게 다른지도 짚어봤다. 설명에서 언급하지 않았지만 React는 제어 컴포넌트로 입력을 처리하는 것을 적극 권장한다. 다만, 상태로 굳이 관리하고 싶지 않거나 적은 코드를 유지하고 싶은 등 특수한 목적을 위해 비제어 컴포넌트를 사용하는 방법도 명시해놓았다. </p>
<p>개인적으로 이 개념을 공부하면서, 컴포넌트에만 맞춰 상태를 설계해야한다는 강박을 없애고, 설계된 컴포넌트에서 상태에 맞춰 단일 상태를 설정하고 필요하면 컴포넌트를 추가한다는 시각을 가지게 되었다.</p>
<p>오늘도 느낀거지만 글로 정리하기 전과 후의 이해도는 하늘과 땅 차이다. 매번 미뤄왔는데 귀찮더라도 꼭 시간을 내서 정리해야겠다.</p>
<p>[참고]</p>
<p><a href="https://legacy.reactjs.org/docs/forms.html"><strong>React 18 Docs - Forms</strong></a></p>
<p><a href="https://ko.legacy.reactjs.org/docs/uncontrolled-components.html"><strong>React 18 Docs - Uncontrolled-Component</strong></a></p>
<p><a href="https://www.youtube.com/watch?v=PBgQKK6nelo&amp;t=253s&amp;ab_channel=%EC%9A%B0%EC%95%84%ED%95%9C%ED%85%8C%ED%81%AC"><strong>[10분 테코톡] 세인의 제어 컴포넌트와 비제어 컴포넌트</strong></a></p>
<p><a href="https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components"><strong>React 19 Docs - Controlled and uncontrolled components</strong></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[개발 블로그 옮김]]></title>
            <link>https://velog.io/@ssg-js/%EA%B0%9C%EB%B0%9C-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%98%AE%EA%B9%80</link>
            <guid>https://velog.io/@ssg-js/%EA%B0%9C%EB%B0%9C-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%98%AE%EA%B9%80</guid>
            <pubDate>Tue, 10 Jun 2025 11:21:49 GMT</pubDate>
            <description><![CDATA[<p>이전에 호기롭게 만들었던 개발 블로그를 제대로 만들지 못해서 리프레시 할 겸, 더 편안한 환경으로 옮길 겸, Velog로 옮겼다. </p>
<p><a href="https://likemath1997.tistory.com/">이전에 만들었던 티스토리 블로그</a></p>
<p>방금 글 하나를 출간해봤는데 확실히 티스토리보다 출간하기 편하고, 마크다운 형식을 그대로 사용할 수 있어서 편하다. 그리고 이미지 업로드도 티스토리보다 간편하다. 
그리고 많은 개발자 분들이 Velog를 사용해서 다른 글을 보기에도 편하고 나름의 소속감도 느껴지는 것 같다 ㅎㅅㅎ
이전 블로그에서 마지막 글로 다짐했던 내용대로 앞으로는 아무리 작은 내용이라도 블로그로 남기려고 노력할 것이고, 1주일마다 편하지만 엄중히 회고글을 남길 것이다.
블로그를 통해 내 생각을 말하고, 기술을 깊이 파고들어 성장하는 발판이 되었으면 좋겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Promise]]></title>
            <link>https://velog.io/@ssg-js/Promise</link>
            <guid>https://velog.io/@ssg-js/Promise</guid>
            <pubDate>Tue, 10 Jun 2025 11:05:47 GMT</pubDate>
            <description><![CDATA[<h3 id="콜백-지옥">콜백 지옥</h3>
<p>자바스크립트에서 콜백 함수는 함수에 인수로 전달되어 함수 내부 동작에서 특정 조건에 맞춰 사용되며, 특히 비동기 함수에서 특정 시점에 맞춰 다양한 동작을 하는데 유용하게 쓰인다. </p>
<p>하지만 콜백 함수로만 작성하면 코드의 가독성이 떨어지는 경우가 발생한다.</p>
<p>다음 코드를 보자.</p>
<pre><code class="language-jsx">function operator(a, b, callback) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      if (typeof a === Number &amp;&amp; typeof b === Number) {
        resolve(callback(a, b));
      } else {
        reject(a, b);
      }
    }, 2000);
  });
}

const promise = operator(1, 2, (a, b) =&gt; a + b);
promise.then((value) =&gt; {
  console.log(value);

  const promise = operator(value, 4, (a, b) =&gt; a * b);
  promise.then((value) =&gt; {
    console.log(value);

    const promise = operator(value, 5, (a, b) =&gt; a - b);
    promise.then((value) =&gt; {
      console.log(value);

      const promise = operator(value, 3, (a, b) =&gt; a * b);
      promise.then((value) =&gt; {
        console.log(value);

        //...
      });
    });
  });
});</code></pre>
<p>여기서 비동기 함수의 결과를 가지고 콜백 함수를 실행하려고 하면, 콜백 함수를 계속 추가하면서 indent(들여쓰기)가 깊어지며 가독성이 안 좋아진다.</p>
<p>만약에 위와 같은 방식이 15개 정도 추가된다고 하면 불편함이 좀 다가올 것이다.</p>
<p>이를 해결하기 위해 Promise를 사용할 수 있다.</p>
<h3 id="promise-객체">Promise 객체</h3>
<p>Promise 객체는 생성자에 인자로 전달된 비동기 함수의 결과를 가진다. </p>
<pre><code class="language-jsx">const promise = new Promise(executor);</code></pre>
<p>여기서 생성자에 전달되는 비동기 함수를 “실제 비동기 작업을 실행하는 함수”라는 의미로 <strong>executor</strong>라고 부른다.</p>
<p>Promise 객체는 <strong>Pending(대기), Fulfulled(완료), Rejected(거절)</strong>이라는 3가지 상태를 가진다.</p>
<p><strong>Pending(대기)</strong>는 executor의 결과를 기다리고 있는 상태,</p>
<p><strong>Fulfilled(완료)</strong>는 executor가 성공적으로 수행되어 결과값을 받은 상태,</p>
<p><strong>Rejected(거절)</strong>는 executor가 예상치 못한 에러를 만나 정상적으로 수행되지 않은 상태이다. </p>
<p>여기서 executor가 성공적으로 수행되었을 때(Pending → Fulfilled)를 <strong>resolve</strong>라고 표현하고,</p>
<p>실패했을 때(Pending → Rejected)를 <strong>reject</strong>라고 표현한다.</p>
<p>executor는 두가지 인자를 가지는데, 순서대로 resolve, reject이다.</p>
<pre><code class="language-jsx">const promise = new Promise((resolve, reject)=&gt;{
  resolve(value);
  reject(errorMessage);
});</code></pre>
<p>resolve 함수를 실행하면 해당 Promise 객체의 상태는 fulfilled가 되고 인수로 넘겨준 값을 결과값으로 갖는다.</p>
<p>아래는 2초 후에 실행되는 비동기 함수의 결과를 기다리고 Promise 객체를 출력하기 위해 3초 후에 객체를 출력하는 코드다.</p>
<pre><code class="language-jsx">const promise = new Promise((resolve, reject) =&gt; {
  setTimeout(() =&gt; {
    resolve(&quot;값&quot;);
  }, 2000);
});
// 2초 후에 resolve된 Promise 객체를 출력하기 위해 3초 기다림
setTimeout(() =&gt; {
  console.log(promise);
}, 3000);</code></pre>
<p><img src="https://velog.velcdn.com/images/ssg-js/post/7a2e9c9b-996c-4811-83ef-3dd204bd820a/image.png" alt=""></p>
<p>reject 함수를 실행하면 Promise 객체의 상태는 rejected가 되고 인자로 넘겨준 값을 결과값을 갖는다.</p>
<pre><code class="language-jsx">const promise = new Promise((resolve, reject) =&gt; {
  setTimeout(() =&gt; {
    reject(&quot;error message&quot;);
  }, 2000);
});
// 2초 후에 reject된 Promise 객체를 출력하기 위해 3초 기다림
setTimeout(() =&gt; {
  console.log(promise);
}, 3000);</code></pre>
<p><img src="https://velog.velcdn.com/images/ssg-js/post/9844c2d9-7350-46ef-8297-9724ef2e1251/image.png" alt=""></p>
<p>콘솔 창에서 보이는 것과 같이 직접 전달한 값과 에러메시지가 출력되는 것을 확인할 수 있다.</p>
<p>하지만 이렇게 3초 뒤에 실행하는 건, 비동기 함수에 2초 후에 실행된다는 것을 알고 있어서 가능한 로직이다. </p>
<p>실제로는 Promise가 언제 resolve or reject 되는지 모르기 때문에 결과를 기다리고 Promise 객체의 상태가 변경되면 결과값을 처리해야 할 무언가가 필요하다.</p>
<h3 id="then-catch-메서드">then, catch 메서드</h3>
<p>then과 catch는 Promise 객체의 메서드이다. then 메서드는 <strong>두 개의 인수</strong>를 받는데 <strong>첫 번째는 resolve 일 때의 콜백 함수</strong>이고, <strong>두 번째는 reject 일 때의 콜백 함수</strong>이다. </p>
<p>여기서 두 번째 콜백 함수는 생략해도 된다.</p>
<p>그리고 catch 메서드의 인수는 reject 일 때의 콜백 함수여서, then 메서드에서 두 번째 인수만 전달된 것의 압축된 표현이라고 할 수 있다.</p>
<p>그래서 위에서 실행한 코드를 바꿔서 결과값을 출력하는 코드로 수정하면,</p>
<pre><code class="language-jsx">const promise = new Promise((resolve, reject) =&gt; {
  setTimeout(() =&gt; {
    resolve(&quot;값&quot;);
  }, 2000);
})

promise.then((value) =&gt; {
    console.log(value);
  });

promise.catch((error) =&gt; {
    console.log(error);
  });</code></pre>
<p>여기서 정말 편리한 점이 있는데, 바로 then과 catch는 Promise 객체를 반환한다는 점이다. </p>
<p>이 말이 무슨 말이냐면, then이나 catch 실행 후 뒤에 다시 then과 catch를 바로 실행할 수 있다.</p>
<pre><code class="language-jsx">promise.then((value) =&gt; {
    console.log(value);
  }).catch((error) =&gt; {
    console.log(error);
  });</code></pre>
<p>이를 체인처럼 연속해서 표현한다고 해서 <strong>체이닝</strong>이라고 말한다.</p>
<h3 id="콜백-지옥-제거">콜백 지옥 제거</h3>
<p>그래서 처음에 만난 콜백 지옥을 Promise를 사용해 제거해보자.</p>
<pre><code class="language-jsx">// promise를 사용한 코드
function operator(a, b, callback) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      if (typeof a === Number &amp;&amp; typeof b === Number) {
        resolve(callback(a, b));
      } else {
        reject(a, b);
      }
    }, 2000);
  });
}

const promise = operator(1, 2, (a, b) =&gt; a + b);
promise.then((value) =&gt; {
  console.log(value);

  const promise = operator(value, 4, (a, b) =&gt; a * b);
  promise.then((value) =&gt; {
    console.log(value);

    const promise = operator(value, 5, (a, b) =&gt; a - b);
    promise.then((value) =&gt; {
      console.log(value);

      const promise = operator(value, 3, (a, b) =&gt; a * b);
      promise.then((value) =&gt; {
        console.log(value);

        //...
      });
    });
  });
});</code></pre>
<pre><code class="language-jsx">// 이전 코드
function operator(a, b, callback) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      if (typeof a === Number &amp;&amp; typeof b === Number) {
        resolve(callback(a, b));
      } else {
        reject(a, b);
      }
    }, 2000);
  });
}

const promise = operator(1, 2, (a, b) =&gt; a + b);
promise.then((value) =&gt; {
  console.log(value);

  const promise = operator(value, 4, (a, b) =&gt; a * b);
  promise.then((value) =&gt; {
    console.log(value);

    const promise = operator(value, 5, (a, b) =&gt; a - b);
    promise.then((value) =&gt; {
      console.log(value);

      const promise = operator(value, 3, (a, b) =&gt; a * b);
      promise.then((value) =&gt; {
        console.log(value);

        //...
      });
    });
  });
});</code></pre>
<p>뭔가 이상하다.</p>
<p>문제가 해결되려면 indent가 들어가지 않고 가독성이 좋아져야 하지만 그렇지 않다.</p>
<p>이를 해결하기 위해 제대로 Promise를 쓰려면 위에서 메서드가 객체를 반환한다는 것을 이용해야 한다.</p>
<p>그래서 다시 수정하면,</p>
<pre><code class="language-jsx">const promise = operator(1, 2, (a, b) =&gt; a + b);
promise
  .then((value) =&gt; {
    console.log(value);

    return operator(value, 4, (a, b) =&gt; a * b); // Promise 객체를 반환해서 체이닝
  })
  .then((value) =&gt; {
    console.log(value);

    return operator(value, 5, (a, b) =&gt; a - b);
    promise;
  })
  .then((value) =&gt; {
    console.log(value);

    return operator(value, 3, (a, b) =&gt; a * b);
    promise;
  })
  .then((value) =&gt; {
    console.log(value);

    //...
  });</code></pre>
<p>이렇게 콜백 지옥을 해결하고 더 나은 가독성을 확보했다.</p>
<p>Promise는 실제로 비동기 함수를 처리할 때 많이 사용하기도 하고, then 메서드 내부에서 Promise 객체를 반환하는 방식은 다른 코드에서도 가독성을 올리는데 유용하게 사용 할 수 있을 것 같다.</p>
<p>[참고]  </p>
<p><a href="https://www.inflearn.com/courses/lecture?courseId=328340&amp;unitId=210869">https://www.inflearn.com/courses/lecture?courseId=328340&amp;unitId=210869</a></p>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise">https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise</a></p>
]]></description>
        </item>
    </channel>
</rss>