HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🐣
프론트엔드 데브코스 3기 교육생
/
📚
3기 스터디 가이드
/
💯
자바스크립트 Deep Dive 스터디
/
🕤
자바스크립트 Deep Dive
/
🥇
41장 타이머, 42장 비동기 프로그래밍 - 동우님
🥇

41장 타이머, 42장 비동기 프로그래밍 - 동우님

41장 타이머

호출 스케줄링
  • 함수를 명시적으로 호출하지 않고 일정 시간이 경과된 이후에 호출되도록 함수 호출을 예약하는 것
  • 이때 타이머 함수를 사용한다.
  • 타이머 함수는 ECMA Script 사양에 정의된 빌트인 함수가 아니라, 브라우저 환경과 Node.js환경에서 모두 전역 객체의 메서드로서 타이머 함수를 제공한다. (⇒ 타이머 함수는 호스트 객체이다.)
  • 자바스크립트 엔진은 단 하나의 실행 컨텍스트를 갖기 때문에, 두 가지 이상의 태스크를 동시에 실행할 수 없다. (⇒ 싱글 쓰레드로 동작한다. )
  • 이런 이유로 타이머 함수는 비동기 처리 방식으로 동작한다.
 
setTimeout / clearTimeout
  • 두번째 인수로 전달된 시간(ms)으로 단 한번만 동작하는 타이머를 생성한다.
    • ⇒ 두번째 인자를 생략하면 기본값인 0이 들어간다.
  • 타이머가 끝나면 첫번째 인수로 전달된 콜백 함수가 호출된다.
    • ⇒ setTimeout의 함수의 콜백 함수는 두번째 인수로 전달받은 시간 이후 한번만 실행되도록 호출 스케줄링 된다.
  • 만약 콜백 함수에 인수를 전달하고 싶다면, 세번째 이후에 적어 전달하면 된다.
  • setTimemout 함수는 생성한 타이머를 식별할 수 있는 고유한 타이머 id를 반환한다.
  • 반환한 타이머 id를 활용해 clearTimeout 함수에서 해당 타이머를 해제할 수 있다.
// 기본 형태 setTimeout(() => console.log('Hi'), 1000); // 콜백 함수에 인수를 전달하려는 경우 setTimeout(name => console.log(`Hi, I'm ${name}`, 1000, 'dongwoo'); // setTimeout을 변수에 할당하는 경우 const timerId = setTimeout(() => conosole.log('id test', 1000); // clearTimeout으로 타이머 해제 하기 clearTimeout(timerId);
 
setInterval / clearIneterval
  • 두번째 인수로 전달된 시간(ms)으로 반복 동작하는 타이머를 생성한다.
    • ⇒ 두번째 인자를 생략하면 기본값인 0이 들어간다.
  • 타이머가 만료될 때마다 첫번째 인수로 전달받은 콜백함수가 호출된다. (타이머가 취소 될때까지 계속)
    • ⇒ setInterval 함수의 콜백함수는 두번째 인수로 전달받은 시간이 경과할때마다 반복 실행되도록 호출 스케줄링이 일어난다.
  • 만약 콜백 함수에 인수를 전달하고 싶다면, 세번째 이후에 적어 전달하면 된다.
  • setInterval 함수는 생성한 타이머를 식별할 수 있는 고유한 타이머 id를 반환한다.
  • 반환한 타이머 id를 활용해 clearInterval 함수에서 해당 타이머를 해제할 수 있다.
// 기본 형태 setInterval(() => console.log('Hi'), 1000); // 콜백 함수에 인수를 전달하려는 경우 setInterval(name => console.log(`Hi, I'm ${name}`, 1000, 'dongwoo'); const timeoutId = setInterval(() => { // 반복 실행이라 이렇게 콜백함수 내부에서도 해제가능 if(count++ === 5) clearInterval(timerId); , 1000}
 
디바운스와 쓰로틀
  • 짧은 시간 간격에 연속해서 발생하는 이벤트들을 그룹화해서 과도한 이벤트 핸들로 호출 방지하는 프로그래밍 기법
    • ex) 짧은 기간 동안 많은 클릭, 짧은 기간 동안 많은 인풋
  • 해당 기법들을 사용하는데 타이머 함수가 사용된다.
  1. 디바운스 (Debounce)
      • 짧은 시간 간격으로 이벤트가 연속해서 발생하면, 이벤트 핸들러를 호출하지 않다가 일정 시간이 경과한 이후에 이벤트 핸들러가 한 번만 호출되도록 한다.
      • 검색, 자동완성, 버튼 중복 클릭 방지 처리 등에 활용된다.
      • 디바운스의 원리
          1. debounce 함수는 timerId를 기억하는 클로저를 반환한다.
          1. delay가 경과하기 이전에 이벤트가 발생하면, 이전 타이머를 취소하고 타이머 재설정
          1. 따라서 delay보다 짧은 간격으로 이벤트가 발생하면 callback은 호출되지 않는다.
          1. delay 보다 짧은 간격으로 input 이벤트가 발생하면 debounce의 콜백 함수는 호출되지 않다가 delay 동안 input 이벤트가 더 이상 발생하지 않으면 한 번만 호출됨
      const $input = document.querySelector('input'); const $msg = document.querySelector('msg'); const debounce = (callback, delay) => { let timerId; return event => { if (timerId) clearTimeout(timerId); timerId = setTimeout(callback, delay, event); } } $input.oninput = debounce(e => { $msg.textContext = e.target.value; }, 300);
      notion image
  1. 스로틀 (Throttle)
  • 짧은 시간 간격으로 이벤트가 연속으로 발생하더라도 일정 시간 간격으로 이벤트 핸들러가 최대 한번만 호출하도록 하는 것
    • ⇒ 짧은 시간 동안 연속해서 발생하는 같은 이벤트를 그룹화해서 일정 시간 단위로 이벤트 핸들러가 호출되도록 호출 주기를 만드는 것
  • 스로틀링의 원리
      1. throttle 함수는 timerId를 기억하는 클로저를 반환한다.
      1. delay가 경과하기 이전에 이벤트가 발생하면 아무것도 하지 않다가, delay가 경과했을 때, 이벤트가 발생하면 새로운 타이머를 재설정한다.
      1. delay 간격으로 callback이 호출된다.
      const throttle = (callback, delay) => { let timerId; return event => { if (timerId) return; timerId = setTimeout(() => { callback(event); timerId = null; }, delay, event); } } document.addEventListener('scroll', throttle(() => { $throttleCount.textContext = ++throttleCount; }, 1000);
      notion image
출처
swift Throttle, Debounce
액션을 일정시간동안 후에 실행
swift Throttle, Debounce
https://docfriends.github.io/DevStrory/2019-01-29/swift-delay/
swift Throttle, Debounce

42 비동기 프로그래밍

  • 자바스크립트에서 함수를 호출하면 함수 코드가 평가되어 실행 컨텍스트를 만든다.
  • 해당 실행 컨텍스트는 실행 컨텍스트 스택. 즉, 콜스택에 쌓이게 되어 함수 코드가 순서대로 실행된다.
  • 함수 코드의 실행이 종료되면 해당 실행 컨텍스트가 스택에서 pop되어 제거되게 된다.
  • 그런데 자바스크립트 엔진은 싱글 쓰레드이다. 단 하나의 실행 컨텍스트 스택을 갖는다는 것이다.
    • 그렇게 되면 딜레이가 있는 경우 블로킹이 발생할 수 있다. ex) sleep 함수
    • 그러나 setTimeout은 딜레이가 있는데도 불구하고, 이후의 태스크를 블로킹 하지 않는다. (how?)
  • 동기 처리: 실행 중인 태스크가 종료될 때 까지 다음에 실행될 태스크 들이 대기하는 방식
    • 실행 순서가 보장된다.
    • 앞선 태스크가 종료할 때까지 이후 태스크들이 블로킹 되는 단점이 있다.
  • 비동기 처리: 실행 중인 태스크가 종료되지 않았더라도 다음 태스크를 곧바로 실행하는 방식
    • 블로킹이 되지 않지만, 실행 순서는 보장되지 않는다.
 
이벤트 루프와 태스크 큐
  • 자바스크립트는 싱글 쓰레드인데, 브라우저가 동작하는 것을 보면 많은 태스크가 동시에 처리되는 것처럼 보인다.
  • 이벤트 루프: 자바스크립트의 동시성을 지원하는 것
notion image
  • 왼쪽이 자바스크립트 엔진
    • 콜스택: 실행 컨텍스트(변수 식별자 저장, 스코프나 this 관리)들이 쌓임, 코드 실행 순서 관리
    • 메모리 힙: Object 타입들의 데이터가 저장된다. (메모리 할당이 일어나는 곳)
      • ⇒ (그래서 const Array ⇒ Array.push, Array.pop값을 바꿀 수 있다.)
    • 자바스크립트 엔진은 단순히 태스크가 요청되면 콜스택을 통해 요청된 작업을 순차적으로 진행한다.
    • 비동기 처리에서 소스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트를 구동하는 환경인 브라우저나, Node.js가 담당한다.
  • 태스크(콜백) 큐
    • Web APIs와 같은 비동기 함수들의 콜백 함수들은 TaskQueue에 순서대로 쌓임. (브라우저가)
    • 태스크 큐와는 별도로 프로미스의 후속 처리 메서드의 콜백 함수가 일시적으로 보관되는 마이크로 태스크 큐가 있다. (마이크로 태스크 큐가 태스크 큐보다 우선순위가 높다.)
    • MacroTaskQueue (Task Queue)
      • setTimeout, setInterval, EventDispatch 등의 콜백함수가 들어간다.
      • 이벤트 루프는 MacroTaskQueue에 있는 task를 하나만 꺼내서 실행한다.
    • MicroTaskQueue
      • Promise의 then, Mutation Observer의 핸들러가 들어간다.
      • 이벤트 루프는 MicroTaskQueue가 빌때까지 task를 꺼내서 실행한다. 1 ← 2
      • task를 처리하는 도중에 queue에 새로운 task가 들어와도 다음 루프로 미루지 않고 쭉 실행
        • 중간에 어떤 코드를 실행시키지 않는다.
      • 우선순위가 가장 높음 ⇒ JS 엔진의 CallStack 이 비자마자 제일 먼저 비워짐
    • AnimationFramesQueue
      • requestAnimationFrames으로 등록된 콜백 함수들이 해당 큐에 들어간다
      • repaint 직전에 queue에 있던 task들을 전부 처리한다.
      • animation에 사용하면 frame drop을 최적화 할 수 있다.
    • 주의할 점
      • 첫째. 비동기 작업으로 등록되는 작업은 task와 microtask. 그리고 animationFrame 작업으로 구분된다.
      • 둘째. microtask는 task보다 먼저 작업이 처리된다. (브라우저 마다 다름)
      • 셋째. microtask가 처리된 이후 requestAnimationFrame이 호출되고 이후 브라우저 랜더링이 발생한다.
  • 이벤트 루프
    • 콜 스택에 현재 실행중인 실행 컨텍스트가 있는지, 태스크 큐에 대기중인 콜백 함수가 있는지 계속해서 확인한다.
    • 콜스택이 비어 있고, 태스크 큐에 대기중인 함수가 있으면 하나씩 콜 스택으로 이동시킨다.
 
 
예시
console.log("script start"); // 실행 콜스택 -> pop // MacroTaskQueue setTimeout(function() { // console.log("setTimeout"); }, 1000); // MicroTaskQueue Promise.resolve().then(function() { console.log("promise1"); }).then(function() { console.log("promise2"); }); // AnimationFrameQueue requestAnimationFrame(function { console.log("requestAnimationFrame"); }) console.log("script end");
 
순서
  1. console.log (script start) 처리된다.
  1. setTimeout 작업이 stack에 등록되고, Web API에게 setTimeout을 요청한다. 이때 setTimeout의 callback 함수를 함께 전달한다. 요청 이후 stack에 있는 setTimeout 작업은 제거된다.
  1. 브라우저는 setTimeout 작업 이 끝난 후(delay 이후), callback 함수가 task Queue에 등록된다.
  1. Promise 작업이 stack에 등록되고, Web API에게 Promise 작업을 요청한다. 이때 Promise.then의 callback 함수를 함께 전달한다. 요청 이후 stack에 있는 Promise 작업은 제거된다.
  1. 브라우저는 Promise 작업이 완료되면 Promise.then의 callback 함수를 microtask queue에 등록한다.
  1. requestAnimation 작업이 stack에 등록되고, 브라우저 에게 reuqestAnimation을 요청한다. 이때 requestAnimation의 callback 함수를 함께 전달한다. 요청 이후 stack에 있는 requestAnimation 작업은 제거된다.
  1. 브라우저는 requestAnimation의 callback 함수를 animation frame에 등록
notion image
  1. console.log('script end')가 처리된다. (callStack이 비워짐)
  1. MicroTaskQueue 부터 콜스택으로 순서대로 이동한다.
      • 해당 then이 실행되고 (콜 스택에서 빠지고), 콜백함수에 또 하나의 then이 있다. 다시 해당 Promise.then의 콜백 함수가 MicroTaskQueue에 쌓인다.
      • MicroTaskQueue는 해당 큐에 있는 모든 task들을 처리해야 끝나므로 두번째 then이 그 다음에 콜스택으로 push 되어 실행된다.
  1. AnimationFrameQueue 가 콜스택으로 순서대로 이동한다.
      • 콜백 함수가 실행되고 콜스택에서 빠진다.
      • 이후 브라우저는 랜더링 작업을 하여 UI를 업데이트한다.
  1. MacroTaskQueue(TaskQueue)의 함수들이 콜스택으로 순서대로 이동해서 실행되고 끝난다~!
결과
script start script end promise1 promise2 requestAnimationFrame setTimeout
 
 
출처
자바스크립트 비동기 처리 과정과 RxJS Scheduler | 아내와 아들 그리고 딸밖에 모르는 남편
오늘 소개할 부분은 작성 중인 책의 "부록" 중 일부이다. 이 장에서는 RxJS Scheduler를 잘 사용하기 위해서 이해해야할 자바스크립트 비동기 처리 과정 을 살펴본다. RxJS를 모르는 사람이라도 자바스크립트의 비동기 처리과정 을 이해하면 자바스크립트를 개발하는데 정말 많은 도움을 준다. 더 자세한 내용은 다음 URL을 참고하여 꼭!
자바스크립트 비동기 처리 과정과 RxJS Scheduler | 아내와 아들 그리고 딸밖에 모르는 남편
https://sculove.github.io/post/javascriptflow/
자바스크립트 비동기 처리 과정과 RxJS Scheduler | 아내와 아들 그리고 딸밖에 모르는 남편
[10분 테코톡] 병민의 브라우저의 Event Loop
[10분 테코톡] 병민의 브라우저의 Event Loop
https://www.youtube.com/watch?v=YpQTeIqjC4o&list=PLgXGHBqgT2TvpJ_p9L_yZKPifgdBOzdVH&index=89
[10분 테코톡] 병민의 브라우저의 Event Loop