반응형

안녕하세요~ 오늘의 5분개발지식라디오! 오늘은 일반적으로는 잘 쓰이지 않는 고급 자바스크립트 문법을 배워보려고 합니다. 어떤 개념인지, 어떤 용도로 쓸 수 있을지를 한번 이야기해보도록 하겠습니다. Proxy에 대한 설명과 예제, 그리고 어떻게 사용할 수 있을지까지 쭉 달려볼 예정이니 끝까지 시청해주세요~

 

먼저 단어의 어원을 알아보겠습니다. Proxy라는 단어의 번역을 보면 “대리”라는 뜻입니다. 단어의 뜻과 동일하게 proxy는 어떠한 객체를 “대리”하는 역할을 합니다.

 

Proxy를 어떠한 객체에 대해서 생성을 하면 타겟 객체의 속성에 대한 읽기, 쓰기 등을 대리해서 먼저 처리할 수 있습니다. 코드를 보면서 이야기하는 것이 더 빠를 것 같습니다.

 

위쪽의 target과 handler를 지나쳐서 프록시를 생성하는 부분을 먼저 보겠습니다. new Proxy를 해서 프록시 객체를 생성할 수 있고, 첫번째 인자로는 프록시할 대상인 타겟 객체, 두번재 인자로는 해당 객체에 오는 요청 중 가로채서 대신할 동작들을 재정의한 메소드로 가지고 있는 handler, 공식용어로는 트랩을 넘겨줍니다.

 

두번째인자인 핸들러의 경우 이미 약속된 이름의 메소드들을 재정의해야됩니다. 가장 일반적으로 쓰일만한 get, set, has, apply들이 먼저 눈에 띕니다. 개발하시면서 가로채고 싶은 동작들을 선택적으로 불러다가 정의하면 됩니다.

 

그럼 다시 코드로 돌아오면 아까보다는 조금 더 이해가 되기 시작합니다. 우리는 target이라는 원본 객체를 프록시하기위해 proxy를 생성했습니다. 그리고 핸들러에는 get 동작을 가로채는 메소드를 추가했습니다. get메소드는 아무런 조건 없이 무조건적으로 world를 반환합니다.

 

그래서 마지막 줄의 콘솔로그를 보시면 proxy의 message1을 조회했지만 world가 찍히는 것을 보실 수 있습니다. 그럼 조금 더 복잡한 심화예제를 보도록 하겠습니다.

 

눈치가 빠르신 분들은 미리 파악하셨을수도 있지만 핸들러의 메소드들은 2가지 변수들을 인자로 받고 있습니다. 첫번째인자는 프록시의 원본 객체이고, 2번째는 코드가 접근하고 있는 속성의 이름을 줍니다. 따라서 현재 보이는 코드처럼 만약 message2를 접근할때는 world를 반환하고 나머지는 그대로 반환하도록 분기처리를 할 수 있습니다.



그래서 프록시는 간단하게 설명을 하자면 원본 객체 접근하기전에 가로채서 내마음대로 요청을 조작할 수 있는 객체인데요, 어떤 경우에 사용하게될까요? 사용방법은 무궁무진하지만 제가 공유드릴 유즈케이스는 유효성 검사, 데이터 싱크, 접근 제어입니다.

 

유효성 검사는 proxy에 대한 설명을 듣다보면 가장 먼저 떠오르는 유즈케이스입니다. 객체에 값이 쓰여질때 가로채서 validation을 통과하는지 확인할 수 있습니다. 코드를 보시죠:

 

자 공용으로 사용하는 person이라는 객체가 있다고 생각을 해보겠습니다. 이 객체는 여러 파일들에서 사용되고 있을때, person 객체에 age라는 속성을 세팅하려고 합니다. age는 나이이기때문에 정수타입으로 저장되고, 200살이 넘는 사람은 없기때문에 200이상을 에러를 내는 것이 타당합니다. 따라서 해당 조건들을 확인하는 setPersonAge라는 함수를 같이 작성해두었다고 하겠습니다.

 

팀으로 작업을하다보면 해당 함수의 존재를 알고 있는 사람도 있지만, 모르고 잇는 사람도 있을 수 있습니다. 아는 사람은 파일A처럼 잘 작성하였지만 setPersonAge라는 함수가 있는지도 모르고 정수로 저장되어야한다는 스펙도 모르는 사람은 파일B처럼 작성할 수도 있습니다. 파일B가 실행된 다음에는 person의 age를 참조하는 코드는 에러가 발생하겠죠.

 

하지만 Proxy를 사용하면 근본적으로 set을 가로채서 유효성검사를 해버릴 수 있습니다. person은 빈객체를 원본객체로 인라인으로 넣어서 원본객체에는 접근이 불가능하도록 만들고 set을 가로챕니다. 그리고 age를 set하려고 하면 유효성검사를 진행하여 필요한 경우 에러를 뱉어줍니다.

 

Proxy는 객체에 값이 변경될때 이를 알아챌 수 있습니다. 이 특징을 사용해서 연관된 다른 값들도 같이 업데이트를 하는 개념인데요, 간단한 예시를 보겠습니다.

 

가끔 프론트엔드 작업을 하시다보면 성과 이름을 입력받는 Input 태그가 분리되어있는 경우가 있습니다. 하지만 유저정보를 수정하거나 생성할때는 이 두개의 값을 합쳐서 하나의 문자열로 보내야되는 경우가 있을 수 있습니다.

 

이런 경우 name이라는 객체에 firstName과 lastName 속성이 업데이트될때 어딘가에 있는 fullName을 같이 업데이트해줄 수 있습니다. 물론 나중에가서 필요할때 합치는 것이 어렵지는 않지만 개념적으로 이해하시면 좋을 것 같습니다. 본 예시처럼 하나의 데이터의 변화를 어딘가에 싱크를 맞춰줘야되는 경우 사용할 수 있습니다. 마치 react의 useEffect를 사용해서 싱크해주는 것과 비슷합니다.

 

Proxy는 속성에 접근할때 이를 가로채고 미리 확인할 수 있습니다. 따라서 사용자가 접근 가능한 속성들을 미리 선언해두고, 이 리스트에 없을 경우 임의로 다른 값을 내려주는 것도 가능합니다.

코드를 보시면 age가 아닌 다른 속성에 접근하려고 하면 ‘ACCESS-DENIED’를 내려줘서 막습니다. 이전에는 특정 속성에 접근하지 못하게 하기 위해 메소드를 통해서만 속성들을 내려주거나 변수명에 특정 기호를 붙여 private 변수임을 명시했는데요,  proxy를 사용하면 이를 원천적으로 차단할수도 있습니다.



자 오늘은 여기까지해서 Proxy에 대해서 알아보았는데요, 영상을 찍다보니 좀 길어졌네요 ㅎㅎ 무궁무진한 사용방법들이 있겠지만 간단하게 느낌을 잡기에는 이 정도면 충분한 것 같습니다. 다른 참신한 사용법이 잇다면 댓글에 공유해주세요

오늘도 같이 공부해주셔서 감사합니다. 유용했다면 구독 좋아요 부탁드립니다.

 

끝!

 

반응형
블로그 이미지

개발자_무형

,
반응형

안녕하세요 오늘의 5분개발지식라디오~ 오늘의 주제는 지난번 영상에 이어 한번 더 React의 신규 기능에 대한 영상입니다. 오늘은 Server component에 대해서 알아볼텐데요, 아직 지난 영상을 보지 않으신 분은 우측 상단의 배너를 누르셔서 시청하고 오시면 훨씬 더 이해가 쉬우실 것 같습니다. 그럼 시작해보겠습니다.

 

서버컴포넌트는 예전 NextJS 영상에서도 언급한적이 있습니다. 서버컴포넌트 또한 서버사이드 렌더링, SSR을 고도화시키기 위한 기능입니다. 서버사이드 렌더링은 서버에서 작업을 마친, 즉 렌더링을 마친 페이지를 클라이언트에게 먼저 보냅니다. 이 페이지는 자바스크립트가 연결되지 않아 사용자와 상호작용이 불가능한 상태인데요, 사용자와 상호작용이 가능하도록하는 과정을 한번 더 거치는데요, 이것을 hydration이라고 합니다.

 

그럼 만약 이런 hydration이 필요없는 컴포넌트가 있다면 어떨까요? 대표적으로 단순히 텍스트를 보여주기만하는 컴포넌트들이 있습니다. 이렇게 서버에서 렌더링이 된 이후에는 추가적인 작업이 필요없다고 구분해둔 컴포넌트들을 서버컴포넌트라고 합니다. 서버컴포넌트는 파일명.js로 쓰는 대신 파일명.server.js로 파일을 생성하면 사용할 수 있습니다.

 

서버컴포넌트는 특히 사용자와 상호작용을 하지는 않지만 무거운 라이브러리를 사용하는 경우 가장 큰 효과를 볼 수 있습니다. 화면의 코드를 보시겠습니다.

 

코드를 보시면 컴포넌트는 marked와 sanitizeHtml이라는 라이브러리를 사용하고 있는데요, 각각 11.2K바이트와 63.3K바이트의 사이즈를 가지고 있습니다. 일반적인 SSR의 경우에는 서버에서 이 2개의 라이브러리를 사용하여 NoteWithMarkdown 컴포넌트를 렌더링을 한 결과를 클라이언트에게 보내고, hydration을 위해서 marked와 sanitizeHtml 라이브러리를 또 보냅니다.

 

하지만 서버컴포넌트를 사용하게되면, React는 서버에서 렌더링을 한 결과물을 보내주면, 클라이언트에서 다시 hydration을 할 필요가 없기때문에 marked와 sanitizeHtml 라이브러리가 필요없다는 것을 알고 있습니다. 그래서 SSR을 한 결과물을 보내준 뒤에 라이브러리 번들은 아예 보내지 않습니다. 클라이언트에서 이 컴포넌트를 hydration하는데 드는 컴퓨팅 비용이 줄어드는 것은 덤이구요.

 

(원래대로)

하지만 주의하실 점은 서버컴포넌트는 처음에 렌더링된 마크업 결과물을 보낸뒤 자바스크립트 번들을 추가적으로 보내지않기때문에 일반적인 컴포넌트처럼 effect나 state를 가질 수 없습니다. 그래도 일반적인 클라이언트 컴포넌트를 내부적으로 사용할 수는 있기 때문에 파일분리를 잘 하시면 문제 없을 것 같습니다. 

 

이 것이 가능한 이유는 내부적으로 클라이언트 컴포넌트를 사용하더라도 코드 스플릿팅으로 인해 사용되는 클라이언트 컴포넌트만 hydration 시킬 수 있기 때문인 것으로 보입니다. 클라이언트 컴포넌트는 서버컴포넌트와 반대로 파일명.client.js로 생성하시면 됩니다.

 

서버컴포넌트가 서버에서만 모든 작업을 처리하기때문에 가능해진 것이 있는데요, 좋은 패턴은 아닌 것 같지만 마치 서버 파일처럼 사용할 수 있습니다. 데이터베이스 접근도 가능하구요. 클라이언트로 보내질 때는 모든 작업이 처리되고 렌더링된 마크업만 전해지기때문에 문제가 없습니다.

 

이 기능은 아직 알파단계에 있습니다. 나중에 React 18버전의 마이너 업데이트로 공식 출시된다고 합니다. 

 

끝!

 

반응형
블로그 이미지

개발자_무형

,
반응형

안녕하세요 오늘의 5분개발지식라디오~ 오늘의 주제는 React인데요, 새로운 렌더링 방식이 나온다고 하여 이에 대해 알아보도록 하겠습니다.

 

저희가 일반적으로 아는 렌더링 방식은 크게 2가지가 있습니다. Client-Side Rendering, CSR이 첫번째고, Server-Side Rendering, SSR이 두번째입니다.

 

간단하게 짚고 넘어가자면, CSR은 서버는 빈 껍데기 HTML파일을 보내주고, 이 HTML파일이 필요한 js파일을 받아오면 이 js파일이 라우팅과 페이지 요소들을 렌더링하는 역할을 하게 되죠.

 

CSR의 장점은 

  1. 유저나 상황별로 다른 파일을 주는 것이 아니기때문에 캐싱이 용이하고 CDN을 사용하기 쉽습니다.
  2. 클라이언트에서 라우팅을 포함한 모든 작업을 처리하기 때문에 페이지 이동간 리프레시가 없습니다. SPA의 장점이기도 하죠.
  3. HTML이 사실상 비어있기때문에 Time To the First Byte(TTFB)가 정말 빠릅니다. 완벽하진 않더라도 사용자가 화면을 조금 더 빨리 받아볼 수 있습니다.

 

하지만 이에따른 단점도 존재합니다.

  1. 클라이언트의 기기에서 모든 작업을 처리하기때문에 어플리케이션이 돌아가는 기기에 따라 성능이슈가 발생할 수 있습니다.
  2. 클라이언트에서 구동에 필요한 js뿐만이 아니라 모든 데이터 fetching까지 진행해야되므로 받아야되는 데이터의 양이 많고 경우에따라 느릴 수 있습니다.
  3. 검색엔진 최적화, SEO에 불리합니다.

 

다음은 SSR에 대해서 알아보겠습니다. SSR은 서버에서 사용자에게 보여주기 위한 HTML안의 내용물을 완성시켜서 사용자에게 내려주는 방식입니다. 이렇게 HTML을 보내준 다음에 사용자의 인터렉션에 반응할 수 있도록 js를 다시 보내줍니다.

 

SSR의 장점은

  1. 검색엔진 크롤러가 접근했을때 완성된 페이지를 바로 받아보기 때문에 검색엔진최적화에 좋습니다. 
  2. 서버에서 모든 작업을 해서 주기때문에 비교적 안정적인 성능을 보여줍니다.

 

반대로 SSR의 단점은

  1. 서버에서 페이지를 만들어서 줘야되기때문에 TTFB가 느립니다.

 

이렇게 CSR와 SSR의 장단점을 알아보았는데요, 이번에 React가 18버전으로 올라가면서 Streaming SSR이라는 새로운 렌더링 방식을 제시하였습니다. CSR과 SSR의 장점을 섞은 차세대 렌더링 방식이라고 볼 수 있을 것 같습니다.

 

브라우저에서는 HTTP stream이라는 것을 열 수 있습니다. 다른 여타 stream과 개념은 동일합니다. 브라우저와 서버가 stream으로 연결되면 서버는 stream을 통해서 브라우저에게 HTML뿐만아니라 데이터를 여러번에 걸쳐서 보낼 수 있게됩니다.

 

일반적인 HTTP연결은 한번 데이터를 보내면 연결이 종료되기때문에 이와는 차이점이 있습니다.

 

이 기능을 사용하는 것이 React18의 신기능, Suspense입니다.

화면의 간단한 예시코드를 보시면 좀 더 쉽게 이해가 될 것 같은데요, 게시물 화면을 간단하게 구성해보았습니다. 여기서 댓글들을 불러오는 Comments가 시간이 오래걸리는 작업이라고 가정을 해보겠습니다.

 

그럼 React는 Comments는 오래걸리기때문에 제외하고 나머지 HTML만을 먼저 구성해서 사용자에게 보내줍니다. 그리고 Comments의 자리는 그냥 비워두는 것이 아니라 처음에 Suspense의 fallback으로 받은 Spinner로 채워서 보내줍니다.



그리고 Comments가 준비가 되면 HTTP stream을 통해서 페이지 전체가 아니라 Comments에 해당하는 HTML부분만 다시 보내줍니다. 일단 HTTP는 한번 데이터를 보내고 나면 connection이 종료되지만 HTTP stream은 유지시킬 수 있고, 이를 통해서 Comments HTML을 준비가 되는대로 뒤늦게 보낸 것입니다. 그럼 사용자는 이전의 일반적인 SSR과 달리 준비가 된 결과물부터 먼저 받아볼 수 있게됩니다.

 

SSR의 장점은 챙기면서 오래걸리는 작업은 빼놓고 먼저 보냄으로서 SSR의 단점을 많이 상쇄시킨 방식이라고 할 수 있습니다.

 

Streaming HTML을 사용하면 HTML을 부분적으로 먼저 받아올 수 있다는 것은 이제 이해했습니다. 하지만 궁극적으로 사용자가 어플리케이션과 인터렉션을 하려면 동작을 위한 자바스크립트 파일도 받아야합니다. 이를 위한 기능이 Selective Hydration입니다.

 

예전에도 React에는 React lazy라는 기능을 사용해서 코드 스플릿팅을 할 수 있었는데요, 문제는 이 기능이 서버에서는 동작하지 않았습니다. 하지만 이제는 Suspense를 사용하면 별다른 코드 추가 없이도 이 기능을 사용할 수 있습니다.

 

아까 봤던 예시 코드를 다시 가져왔습니다. 이렇게 Comments를 Suspense로 감싸게되면 Comments의 자바스크립트 코드는 자동으로 다른 번들로 코드 스플릿팅이 되며, HTTP stream을 통해서 보낼때 알아서 제외하고 보냅니다. 이제 자바스크립트 번들도 Comments를 포함할 필요가 없기때문에 사이즈도 더 작아지는 효과도 있습니다.

 

반응형
블로그 이미지

개발자_무형

,
반응형

 

 

오늘의 5분 개발지식 라디오! 안녕하세요~ 오늘은 NextJs가 2022년 10월말에 새로 메이저 넘버링 업데이트가 되어 간략하게 살펴보려고 합니다. 새롭게 13버전이 출시되었네요~

 

 

먼저 page폴더가 없어지고 app폴더가 생깁니다. 그와 동시에 예약된 파일명들을 통해서 주로 많이 사용되는 기능들을 쉽게 추가할 수 있게 되었습니다.

 

간략하게 살펴보자면 기존에 pages안에 생성하던것과 동일하게 자신이 생성하고 싶은 경로명으로 폴더를 생성하면되는데요, 각각의 파일이 개별적인 경로가 되던 것이 이제는 page.js가 UI를 나타내도록 변경되었습니다.

 

화면을 보시면 예전에는 pages 폴더 하위의 모든 파일들이 하나의 경로였다면 이제는 app하위에서 page라고 지어진 파일만 접근이 가능합니다. 예전에는 컴포넌트를 쪼갤때 pages밖에 따로 분리했어야됐다면 이젠 app안에 같이 정리해둘 수 있을 것 같네요.

 

 

그 외에도 많은 페이지들에 기본적으로 들어가는 layout, loading, error 등은 예약된 파일로써 지원한다고 합니다.

 

다만 13버전에서는 기존의 pages를 새로운 app과 동시에 사용이 가능하다고 하니 점진적으로 마이그레이션이 될 수 있을 것 같긴합니다. 하지만 pages의 지원이 중단되는 시점부터는 더이상 next 버전을 간단하게는 올릴 수 없는 레거시 코드가 될 것 같네요.

 

 

13버전부터는 app폴더안에 들어가는 컴포넌트들은 기본으로 React Server Component가 된다고 합니다. Server component는 서버에서 렌더링되는 컴포넌트이고, 반대로 Client component는 클라이언트에서 받아서 렌더링되는 컴포넌트입니다. Server component는 필요한 자바스크립트 작업들을 최대한 다 해서 클라이언트에게 보내주기 때문에 클라이언트가 받게되는 js파일 사이즈가 줄어든다고 합니다.

 

추가적으로 이제는 streaming 기능을 지원하여 데이터를 기다릴 필요가 없는 부분은 먼저 보내서 사용자에게 보내주고 나머지 기다려야되는 부분은 로딩상태로 보여준다고 합니다. 사용자들에게 더 빠른 피드백을 줄 수 있을 것 같습니다.

 

 

Next13에서는 번들링툴로 Turbopack이 추가된다고합니다. vercel측에 따르면 웹팩보다 700배빠르고, Vite보다 10배빠르다고 합니다. 

 

그 외의 자잘한 변경사항들은 스킵하도록 하겠습니다

 

next의 13버전을 사용하려면 최소 18.2버전의 React가 필요하고, 14.6버전의 노드가 필요합니다. 그리고 이제는 더이상 인터넷 익스플로러를 지원하지 않는다고 하네요.

 

끝!

 

반응형
블로그 이미지

개발자_무형

,
반응형

오늘의 5분 개발지식 라디오! 안녕하세요~ 오늘은 브라우저에서 유저의 눈에 보이도록 렌더링을 하기까지의 과정을 간략하게 정리해보려고 합니다.

 

렌더링 파이프라인의 처음 시작은 HTML과 CSS를 파싱하는 작업부터 시작합니다.

개발자가 작성한 HTML과 CSS를 분석하여 각각의 태그들의 구조도인 Document Object Model, DOM을 만듭니다. 트리형태로 생성이 되기때문에 DOM트리라고도 합니다. 

 

CSS도 비슷한 방식으로 각각의 태그들이 가져야될 스타일을 트리형태로 생성하는데 이것을 CSS Object Model, CSSOM 트리라고 합니다.

 

이 과정에서 유의할점은 DOM트리 생성을 위해 HTML을 파싱할때, script 태그를 만나게되면 병렬로 진행하는 것이 아니라 잠시 파싱을 멈추고 script태그를 먼저 처리합니다. 

 

그 이유는 스크립트에 노드 구조를 변경할 수 있는 코드가 있을수도 있기때문인데요, 따라서 스크립트가 어느 위치에 삽입되느냐에 따라서 초기 로딩 속도가 차이날수도 있습니다.

 

이렇게 HTML과 CSS를 사용하여 DOM 트리와 CSSOM 트리를 생성하면 Recalculate style이라는 단계를 통해 DOM트리와 CSSOM트리를 합쳐 Render tree를 생성합니다. 여기서 특이한점은 실제로 화면에 보여지는 노드만을 가지고 있게되는데 css의 display none이 적용되면 눈에 보이지 않기때문에 render tree에서는 삭제됩니다.

 

자 다음은 Layout 단계인데요, 이전의 recalculate style의 결과물인 render tree에는 화면에 그려져야 될 모든 노드의 계층구조와 스타일을 포함하고 있습니다. Layout 단계에서는 해당 정보들을 사용하여 모든 노드들의 크기와 위치를 계산합니다. 

 

예를 들어 개발자가 display: flex를 적용하였다면 안에 포함된 노드들이 어떤 사이즈로 어떤 간격으로 배치될지 정확한 수치가 계산되는 단계로 보시면됩니다. 실제 노드들의 크기와 위치를 결정하는 단계로 브라우저 사이즈인 view port와 폰트 사이즈에 매우 종속적인 단계입니다. viewport와 폰트사이즈가 변경되면 위치와 사이즈가 모두 재계산되야되므로 layout 단계부터 재실행됩니다.

 

마지막은 Paint단계인데요, Layout 단계에서 계산된 정보를 가지고 그래픽카드에서 실제로 픽셀단위로 그려주는 역할을 합니다. 마치 초등학교에서 그리던 점묘화를 그리는 것 처럼 화면의 각 픽셀에 어떤 색이 들어갈지를 다 세팅하여 화면에 송출하기 전 단계입니다.

 

이렇게 모든 과정이 끝나면 화면에 어떻게 하나의 페이지가 그려져야될지 그래픽카드의 메모리에 저장되게 되고 사용자가 볼 수 있게됩니다. 각각의 단계가 이전 단계의 결과물을 사용하여 점진적으로 진행되기 때문에 파이프라인이라고 부릅니다. 전체의 과정이 화면에 렌더링하기 위한 과정이기때문에 렌더링 파이프라인이라고 부르는 것입니다.

 

지금까지의 설명은 브라우저의 가장 핵심적이고 기본적인 과정만을 담고 있기때문에 최신 브라우저들은 지금까지 설명드린 내용 이상으로 여러가지 추가적인 기법들과 단계들을 통하여 최적화를 하고 있습니다.

 

끝!

 

반응형
블로그 이미지

개발자_무형

,
반응형

안녕하세요 기존의 영상들과 더불어 이제 면접에서 나오는 질문들이나 주제들을 모아서 면접지식 시리즈를 시작해보려고 합니다. 오늘은 프론트엔드 쪽으로 취준을 하시면 자주 나오는 질문인 쓰로틀링과 디바운스에 대해서 알아보려고 합니다.

 

쓰로틀링과 디바운스 모두 프론트엔드에서 성능 최적화를 위해서 사용됩니다. 특정 이벤트에 로직을 붙일 때 로직이 실행되는 횟수를 제한하는 것이 목적이지만 동작방식이 조금씩 차이가 있는데요,

 

—-

먼저 쓰로틀링입니다.

쓰로틀링은 한번 로직이 실행되고 나면이후 정해진 시간동안은 해당 로직의 실행을 막는 방식입니다. 

화면에서 보이다시피 처음 0초에 이벤트가 발생되었기때문에 로직이 실행됩니다. 현재 화면의 예시는 쓰로틀링을 3초로 걸었기때문에 1초와 2초에 발생한 이벤트에 대해서는 로직이 실행되지 않습니다. 그 후 3초가 지났기때문에 3초에 발생한 이벤트에 대해서는 다시 로직이 실행됩니다.

 

이런 방식으로 한번 로직이 실행되고 나면 일정 시간동안 로직의 재실행을 막는 것을 쓰로틀링이라고 합니다. 이벤트 발생 시에 수행되는 이벤트 핸들러는 로직 실행가능여부를 판단하여 로직을 실행하는데요.

 

 

첫번째 방식으로는 로직을 실행한 후 로직 실행가능여부를 false로 바꾸고 타이머를 세팅하여 정해진 시간이 지난후 true로 변경해주는 방식으로 작성이 가능하고 두번째로는 로직이 마지막으로 수행된 시간을 저장해두고 이벤트 핸들러에서 이벤트가 발생했을때의 시간을 저장된 마지막 로직 수행시간과 비교하여 실행여부를 판단할 수 있습니다.

 

다음은 디바운스입니다.

디바운스는 이벤트발생이 종료되고 정해진 시간이 지날동안 이벤트가 다시 발생하지 않으면 로직을 실행하는 방식입니다. 정해진 시간이 지나기 전에 다시 이벤트가 발생한다면 다시 처음부터 그 시간을 기다립니다. 

 

화면을 보시면 0초에 최초로 이벤트가 발생하여 3초까지 대기하다가 로직을 실행하려고 합니다. 하지만 1초에 다시 이벤트가 발생했기때문에 4초까지 기다리도록 타이머가 초기화되었고, 2초에도 동일하게 초기화되어 5초까지 기다리게됩니다. 그 후 3초와 4초에는 이벤트가 발생하지않았기때문에 5초에 예약되었던 로직이 실행됩니다.

 

 

디바운스는 이벤트 핸들러에서 로직 수행을 위한 타이머가 세팅되어 있는 지를 확인합니다. 세팅되어있지 않다면 정해진 시간 후에 로직이 수행하도록 타이머를 세팅합니다. 만약 이미 타이머가 세팅되어있다면 세팅된 타이머를 초기화하거나 제거한 후 새로 세팅합니다.

 

그럼 언제 어떤 방식을 사용해야할까요?

이건 전적으로 어떠한 문제를 어떠한 방식으로 해결할지에 달렸습니다. 본인의 서비스의 사용자들의 사용방법에 따라 다르기도하구요. 둘다 적용될 수 있는 문제를 예시를 들어 장단점을 설명드리겠습니다.

 

가장 대중적인 예시로 스마트폰에서 사용하는 지도 어플리케이션을 생각해보겠습니다. 이름이 프레임워크나 언어별로 다를 수 있지만 일반적으로 저희가 지도를 살펴보기 위해 터치로 쭉 끌어서 이동하는 경우 발생하는 이벤트를 drag라고 생각해보겠습니다.

 

이런 drag이벤트는 사용자가 드래그를 하는 동안 수십수백번 실행되는데요, 현재 화면의 지도에 보이는 영역에 있는 카페를 검색하기 위한 API가 호출된다고 생각하면 1초에 수십번 호출되는 것입니다. 

 

1분동안 사용된다고 하면 수천번 호출되는 것이고 천명의 사용자가 동시에 사용한다면 몇백만번 이상의 API호출이 일어나 서버에 과부하가 일어나게됩니다. 이렇게 서버 호출 뿐만이 아니라 복잡한 계산이 들어가는 경우에도 불필요하게 많이 반복됨으로 인해 부하가 일어나고 사용자의 화면에서 버벅임이 일어나기도 합니다.

 

그럼 쓰로틀링을 적용하면 어떻게 될까요? 이 경우 쓰로틀링을 적용하면 사용자가 드래그를 시작하고 3초마다 한번씩만 카페 검색 API를 호출합니다. 장점은 사용자가 드래그를 하는 동안 계속해서 현재 위치의 카페들을 볼 수 있습니다.

 

반대로 디바운스를 적용하면 사용자가 드래그를 멈출때까지 API가 호출되지 않고 드래그를 멈추면 최종 화면의 위치에 있는 카페들을 검색합니다. 쓰로틀링에 비해서 API호출 횟수가 적은점은 장점이지만 드래그를 하는 도중에는 화면에 카페가 보여지지 않습니다.

 

위의 예시에서 만약 본인의 팀이 사용자의 사용성을 더 우선시한다면 쓰로틀링을 적용할 것이고, 서버의 비용을 줄이고 싶다하면 디바운스를 적용할 수 있을 것 같은데요, 앞서 말씀드렸다시피 정답이 있다기보다는 현재의 상황에 따라 다를 것 같네요.

 

끝!

 

반응형
블로그 이미지

개발자_무형

,
반응형

오늘의 5분 개발지식 라디오! 안녕하세요~ 오늘은 타입스크립트에 대해서 이야기해보려고 합니다.

 

> 생긴 이유 (장점)

일단 타입스크립트가 왜 생겼는지를 먼저 알아보려고 하는데요, 타입스크립트랑 이름이 비슷한 친구가 있죠? 네 맞습니다. 자바스크립트가 있는데요, 타입스크립트는 이 자바스크립트에서 파생된 언어입니다. 자바스크립트는 동적 타입 언어로 개발자들이 코딩을 할 때 각 변수들이 어떤 타입인지를 명시하지 않습니다. 때문에 개발을 하다보면 로직상의 오류로 개발자가 의도한 타입이 아닌 경우가 있는데요, 



예를 들어 a와 b를 더하는 함수를 작성했다고 했을 때, 위의 코드는 에러없이 동작하는 매우 정상적인 코드입니다만, 개발자의 의도는 이게 아니죠. 

 

이렇게 오류없이 돌아가지만 의도한 동작이 아닌 경우도 있고, 아예 코드가 동작하지 않아서 빈화면이 뜨거나 멈춰버리는 경우도 많이있습니다.



따라서 타입스크립트는 변수에 타입을 명시하도록해서  정적분석을 통해 런타임에서 발생할 수 있는 에러를 미리 해결할 수 있도록 합니다. 화면에서 보이는 것처럼 IDE에서 빨간줄로 힌트를 주는 경우도 있고, 빌드타임에 에러가 발생해서 미리 검출하고 미리 해결할 수 있습니다. 

 

만약 타입스크립트처럼 미리 잡아주지않으면 실제 프로덕션 환경에 배포되어 사용자들이 피해를 본 다음에 고칠 수 밖에 없겠죠. 물론 타입스크립트는 타입관련 에러만 잡아주기때문에 그 외의 로직상의 오류는 당연히 스스로 찾아야 합니다만, 제 경험상으로 타입 관련 오류만 잡아주더라도 전체 발생하는 오류의 반 정도는 사전에 예방이 되는 것 같습니다.

 

이 외에도 미리 타입을 정의하고 작업을 하기때문에 경우에 따라선 조금 더 계획적으로 접근할 수 있기도 합니다.

 

타입스크립트에서 타입 명시는 필수가 아니며 여러가지 옵션들을 통해 조절을 할 수 있고, 바닐라 자바스크립트로 작성하더라도 정상적으로 동작합니다. 즉, 타입스크립트는 자바스크립트의 superset, 확대집합으로서 타입 정의와 체킹만 추가한 것으로 보셔도 됩니다.

 

> 트랜스파일러

하지만 문제가 하나 있습니다. 우리가 사용하는 크롬, 웨일, 사파리 등의 브라우저는 “타입스크립트"라는 언어를 이해하지 못합니다. 타입스크립트엔진이 아닌 자바스크립트 엔진만을 내장하고 있기 때문이죠. 오직 자바스크립트밖에 이해하지 못하는데요, 그럼 우리는 어떻게 타입스크립트를 사용할 수 있을까요?

 

여기서 트랜스파일이라는 개념이 등장하는데요, 

어 트랜스파일? 컴파일은 들어봤는데?라고 생각하실 수 있습니다.

 

컴파일은 더 높은 수준으로 추상화된 언어(high level language)를 그보다 낮은 수준으로 추상화된 언어(low level language)로 변환하는 작업을 뜻합니다. c언어를 머신코드로 바꿔주는 작업이 바로 컴파일인것이죠.

 

트랜스파일은 비슷한 개념이지만 더 낮은 추상화레벨로 바꿔주는 것이 아닌 비슷한, 또는 동일한 레벨의 언어로 바꿔주는 작업입니다. 자바스크립트는 머신코드와 같은 더 낮은 레벨은 언어라고 볼 수는 없기 때문에 컴파일이 아닌 트랜스파일이라고 합니다.

 

정리해보자면, 브라우저는 타입스크립트를 이해할 수 없기때문에 자바스크립트로 변환을 해서 실제 브라우저에서 돌리게 됩니다.




> 단점

  • 하나의 절차가 더 추가되니까 비효율적인 것 아닌가?

자 여기까지 잘 따라오셨으면 문득

 

아니, 그냥 자바스크립트로 작성하면바로 브라우저에서 실행할 수 있는데 괜히 타입스크립트로 작성하면 코드도 트랜스파일해야되고 괜히 빌드 타임만 늘어나고 비효율적인거 아니야?

 

라고 생각이 드실 수 있습니다.

 

합리적인 추론이긴 한데요, 현실은 생각보다 녹록치 않습니다. 프론트엔드용 코드는 개발사가 세팅해둔 서버에서 돌아가는 것이 아니라 각각의 사용자의 디바이스에서 돌아갑니다. 이 디바이스는 최신 안드로이드일 수도 있고, iOS일 수도 있으며, 윈도우 PC일 수도 있습니다. 또, 극단적으로 이제 더이상 업데이트가 지원되지 않는 갤럭시 S2일 수도 있습니다. 이 경우 최신 자바스크립트 문법이 동작하지 않을 수 있는데요, 이러한 기기들을 지원하기 위해 polyfill을 사용하여 구형 자바스크립트 엔진에서도 돌아갈 수 있도록 코드를 변환합니다.

 

즉, 프론트엔드의 코드는 거의 항상 개발작업을 마치면 배포 전에 pollyfill 작업을 통해 코드를 변환하는 작업을 거치게 됩니다. 이 과정에서 최적화를 위해서 코드양을 줄이는 minification 등도 거치게되죠. 따라서 이 과정들과 함께 타입스크립트를 자바스크립트로 변환하면 되니까 크게 작업성에 문제가 되지 않는 것이죠.

 

정리하자면, 이왕 코드 작업 마치고 브라우저 호환성과 최적화를 위해서 변환작업을 거칠꺼면, 개발할 때 안정성과 편리함을 위해서 타입스크립트를 사용하고 같이 변환해버리자~ 가 된 것입니다.



  • 코드양이 늘어나는 것 아닌가?

정적 타입을 사용하는 언어를 처음 접하게 되면 가장 먼저 들 수 있는 생각이 비즈니스 로직만 작성하면 되는데 쓸데없이 변수 타입까지 선언해줘야되서 코딩하는 것이 늘어나는 거 아니야?라고 생각하시는 분들이 많습니다.

 

이건 사람마다 조금씩 생각이 다를 수는 있는데요, 제 개인적인 생각으로는 개발자는 사람이기 때문에 필연적으로 실수를 하게 되어있는데요, 바닐라 자바스크립트를 사용할 때는 이 버그를 실제 페이지를 접근해서 오류가 발생해 빈화면이 떠야지만 그제서야 검출할 수 있었습니다. 타입스크립트를 사용하면 visual studio code와 같은 IDE에서 개발 중에 바로 에러를 표시해주기 때문에 오히려 제 기준에서는 생산성이 더 높아졌습니다.

 

또, 타입스크립트에서는 객체가 어떤 속성을 가지고 있는지 미리 선언해야되기때문에 IDE가 어떤 속성이 있는 지를 미리 알 수 있고, 따라서 속성을 타이핑할때 자동완성이되어 끝까지 치지않아도 되기때문에 작업속도가 더 빨라지는 것 같기도 합니다.

 

(^ 31)







> 최신 이슈

하지만 최근에는 타입스크립트를 자바스크립트로 변환하는 과정이 작업성을 저해한다는 의견도 조금씩 나오고 있습니다. 이는 최신 브라우저들의 발전때문인데요, 예전과 달리 브라우저들이 스스로 업데이트를 하면서 항상 최신 상태를 유지하는 기능을 많이 가지고 있는데요, 이런 브라우저들을 evergreen 브라우저라고 합니다.

 

이런 브라우저들이 많아지게되면 더이상 개발자가 브라우저 호환성을 신경쓸필요가 없어지게되고, 그럼 pollyfill을 사용하여 자바스크립트 변환이 필요없어지는 때가 온다는 것이죠. 그럼 트랜스파일하는 과정은 온전히 타입스크립트를 자바스크립트로 변환하기 위한 것이 되고, 이는 불필요한 작업성 저하라는 의견이 나오고 있습니다.

 

하지만 타겟 사용자가 구형 디바이스를 사용할 가능성이 높거나 이런 사용자도 다수 포함되어있는 오래된 서비스나 대기업에서 제공하는 서비스들은 어쩔수없이 꽤 오랜 시간 동안 브라우저 호환성을 신경쓸 수 밖에없기도 하고 everygreen 브라우저가 대세가 되기 위해서는 아직은 시간이 더 걸릴 것으로 보여 제 개인적으로는 타입스크립트가 한동안은 기본으로 쓰이는 언어가 되지 않을까 싶습니다

 

반응형

'프론트엔드' 카테고리의 다른 글

Rendering pipeline 쉽게 이해하기  (0) 2023.04.26
Debounce vs Throttling 이해하기  (0) 2023.04.26
WebRTC 기본 개념 정리  (0) 2020.12.24
Janus screen sharing 만들기  (1) 2020.03.19
Janus media server 설치하기  (4) 2020.03.17
블로그 이미지

개발자_무형

,
반응형

4줄요약:

  1. WebRTC는 peer-to-peer communication을 하기 위해 signaling이라는 process를 거쳐야한다.
  2. Peer-to-Peer 연결을 하기 위해 ICE Framework를 사용하며 UDP > TCP > STUN > TURN(relay)순으로 시도한다.
  3. 연결이 되었으면 offer-and-answer mechanism으로 서로의 media capability를 교환한다. 자신의 RTCPeerConnection 인스턴스에 상대방의 자신과 상대방의 정보를 저장한다.
  4. RTCPeerConnection의 등록된 정보로 서로 연결하고 communication이 이루어진다.

Signaling: process of coordination communication. In order for a WebRTC app to set up a call, its client need to exchange the following information:

  • Metadata (codec, bandwidth, etc)
  • Network data (IP addr, port, etc)
  • etc

To avoid redundancy and to maximize compatibility with established technologies, signaling methods and protocols are not specified by WebRTC standards. You can use socket to build signaling services.

 

RTCPeerConnection: API used by WebRTC apps to create connection between peers and communicate audio and video. RTCPeerConnection has two tasks:

  • Obtain local media conditions (resolutions, codec capabilities) using offer-and-answer mechanism.
  • Obtain potential network address for the app's host, known as candidates.

Offer-and-answer mechanism (A is calling B):

  1. A creates RTCPeerConnection object
  2. A creates an offer with createOffer()
  3. A calls setLocalDescription() to send A's setup to B
  4. A stringifies offer and sends it to B using signaling mechanism
  5. B calls setRemoteDescription() so that B's RTCPeerConnections knows about A's setup
  6. B calls createAnswer()
  7. B calls setLocalDescription() to send B's setup to A
  8. B stringifies offer and sends it to A using signaling mechanism
  9. A calls setRemoteDescription() so that A's RTCPeerConnection knows about B's setup

Very similar to handshake procedure

 

 

ICE framework: framework used to find network interfaces and ports (candidates)

In reality most devices live behind one or more layers of NAT, some have antivirus SW that blocks certain ports and protocols. You can use ICE framework to overcome complexities. To enable this to happen, your app must pass ICE server URLs to RTCPeerConnection. ICE tries to find the best path to connect peers.

ICE tries to find the best path to connect peers. It tries all possibilities in parallel and chooses the most efficient option that works.

  1. ICE first tries to make a connection using the host address obtained from a device's OS and network card.(UDP > TCP)
  2. If that fails(which it will for devices behind NATs), ICE obtains an external address using a STUN server.
  3. If that fails, traffic is routed through a TURN relay server.
    Every TURN server supports STUN. A TURN server is a STUN server with additional built-in relaying functionality.

STUN: NATs provides an IP address for use within a private local network to a device but this can't be used externally. You need a public address. WebRTC uses STUN get around this problem. STUN server live on the public internet and check the IP:port address of an incoming request (from an app running behind a NAT) and send that address back as a response. In other words, the app uses a STUN server to discover its IP:port from a public perspective.

 

TURN: RTCPeerConnection tries to set up direct communication using UDP. if that fails, it tries TCP. if that fails, TURN servers are used to relay data. TURN is used to relay audio, video, and data streaming between peers, not signlaing data. TURN servers have public addresses, so they can be contacted by peers even if the peers are behind firewalls or proxies.

Reference:
www.html5rocks.com/en/tutorials/webrtc/basics/
www.html5rocks.com/en/tutorials/webrtc/infrastructure/
www.html5rocks.com/en/tutorials/webrtc/datachannels/

반응형
블로그 이미지

개발자_무형

,