자바스크립트 중요 개념 정리

은아·2024년 8월 18일

면접 대비 정리

목록 보기
2/5

자바스크립트는 어떤 언어인가요?

자바스크립트는 하나의 콜스택을 갖는 단일 스레드 기반 언어이자 동적 언어입니다.

📌 자바스크립트의 특징

  • JS 엔진은 단 하나의 실행 컨텍스트 스택(=콜 스택)을 갖는다.
  • JS 엔진은 싱글 스레드 방식으로 동작한다.
    *싱글 스레드single thread란?
    한 번에 하나의 task만 실행가능한 방식이다.
    ‼️ 하지만, 브라우저는 멀티 스레드로 동작한다 ‼️

콜백함수(Callback Function)란?

자신이 아닌 다른 함수에, 인수로써 전달된 함수를 의미 함

자바스크립트 가비지 컬렉션 알고리즘

가비지 컬렉션은 더 이상 사용되지 않는 메모리를 자동으로 해제하는 중요한 프로세스

  • 마크 앤 스윕 (Mark and Sweep):
    대부분의 현대 브라우저에서 사용하는 주요 알고리즘입니다.
    루트(전역 객체, 현재 함수의 지역 변수 등)에서 시작하여 도달 가능한 모든 객체를 마크합니다.
    마크되지 않은 객체는 가비지로 간주되어 스윕(제거) 됩니다.

  • 세대별 수집 (Generational Collection):
    객체를 "새로운" 객체와 "오래된" 객체로 분류합니다.
    새로운 객체는 더 자주 검사하고, 오래된 객체는 덜 자주 검사합니다.
    많은 객체가 생성 직후에 불필요해진다는 관찰에 기반합니다.

  • 증분 수집 (Incremental Collection):
    전체 힙을 한 번에 검사하지 않고 작은 부분으로 나누어 점진적으로 수행합니다.
    가비지 컬렉션으로 인한 일시 중지 시간을 줄입니다.

이러한 알고리즘들은 자바스크립트 엔진에 따라 다양하게 구현되고 최적화됩니다.
예를 들어, V8 엔진(Chrome, Node.js)은 마크 앤 스윕을 기반으로 하되 세대별 수집과 증분 수집 기법을 결합하여 사용합니다.

이벤트루프

1️⃣ 이벤트 루프란 무엇인가요?
여러 비동기 함수가 실행되면, 브라우저와 싱글 스레드 방식으로 동작하는 자바스크립트 엔진이 함께 처리합니다.
여기서 이벤트 루프는 실행 컨텍스트가 생기고 없어지는 JS 엔진의 콜스택과 비동기 함수의 콜백 함수나 이벤트 핸들러가 일시적으로 보관되는 브라우저의 태스크 큐를 반복적으로 확인하여 콜 스택이 모두 비어있으면 태스크 큐에 대기 중인 함수를 선입선출 방식으로 콜 스택으로 이동시키는 역할을 하는 브라우저 내장 기능입니다.

이벤트 루프event loop 덕분에
많은 task가 동시에 처리되는 것처럼 보인다!(자바스크립트의 동시성)

스코프

1️⃣ Scope란 무엇인가요?
규칙에 따라 식별자(변수, 함수, 클래스)에 접근할 수 있는 범위가 존재하는데, 이 식별자 접근 규칙에 따른 유효 범위를 스코프라고 합니다. 스코프에는 Global Scope와 Local Scope, Block Scope와 Function Scope가 있습니다.

변수나 함수에 접근하거나 호출할 수 있는 범위를 말함!

var, const, let 변수 호이스팅 (var 쓰지마...)

1️⃣ var, let, const의 차이점을 설명해주세요.
var과 let은 둘 다 재할당이 가능하다는 공통점이 있지만 var은 재선언이 가능하고, let은 재선언을 할 수 없습니다. 그와 달리 const는 재선언과 재할당이 모두 불가능합니다.
또한, var은 함수 스코프를 따르지만 let과 const는 블록 스코프를 따른다는 점에서 차이가 있습니다.

2️⃣ var과 let 중 무엇을 더 선호하는지, 그 이유는 무엇인지 설명해보세요.
저는 let 사용을 더 선호합니다.
var은 재선언과 재할당이 모두 가능합니다. 또한 함수 스코프를 따르는 var의 특성 때문에 지역 스코프로 선언한 변수가 전역 스코프에서도 접근, 참조가 가능해지므로 예측하지 못한 오류가 발생할 가능성이 큽니다. 그래서 더 예측 가능한 코드를 작성하기 위해 블록 단위로 스코프가 구분되는 let 사용을 더 선호하게 되었습니다.

3️⃣ 전역 변수를 지양해야 하는 이유는 무엇인가요? 어떻게 하면 전역 변수 사용을 줄일 수 있나요?
전역 변수는 어디서든 접근이 가능해서 의도치 않은 로직으로 인한 문제가 발생하기 쉽기 때문에 자제 해야합니다. 특히 전역 변수를, 블록 스코프를 무시하고 재선언과 재할당이 가능한 var로 선언하는 경우 문제가 더욱 심화될 수 있습니다.
이를 해결하기 위해서는 변수를 함수 안에 넣어 지역 변수로 만들거나 네임스페이스(객체 안에 속성)로 만들면 됩니다. 하지만 네임스페이스 내의 변수도 외부에서 접근하여 쉽게 바꿀 수 있기 때문에 함수로 감싼 후 공개할 변수만 return하는 방법도 사용할 수 있습니다.

const는 상수를 만드는 것, 변하고 싶지 않은 값들을 만들 때 쓰인다.

let과 var는 자바스크립트에서 변수를 선언하는 두 가지 방법으로, var가 먼저 도입되었고 let은 ES6에서 추가되었다.

  • 호이스팅은 함수가 실행되기 전에 안에 있는 변수들을 범위의 최상단으로 올라가는 자바스크립트의 특징이다.

var는 호이스팅 시 변수 선언과 초기화가 동시에 이루어져 undefined로 초기화되지만, let은 선언만 호이스팅되고 초기화는 나중에 이루어진다.

  • let은 변수의 중복 선언을 허용하지 않고, 블록 스코프를 가지며, TDZ(Temporal Dead Zone: a가 호이스팅으로 기억이 된 건 알겠지만 하지만 a 선언문이 나오기 전까진 너는 a에 접근할 수 없어!)
    를 통해 선언 전 접근을 막아 var의 문제점을 해결한다.

현대 자바스크립트에서는 var 대신 let을 사용하는 것이 권장되며, 이를 통해 더 안전하고 예측 가능한 코드를 작성할 수 있다.

참고: https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/main/JavaScript#hoisting

실행 컨텍스트 Execution Context

  • 정의: 자바스크립트 코드가 실행되는 환경을 나타내는 추상적인 개념이다.
    식별자를 등록하고 관리하는 스코프와 코드 순서 관리를 구현한 내부 매커니즘으로 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.

  • 구성 요소:
    a) 변수 객체 (Variable Object): 지역 변수, 매개변수, 함수 선언 등을 포함
    b) Lexical Environment(변수, 함수 등의 정보를 담은 환경을 나타내는 객체: 자신의 외부 환경에 대한 참조를 가지고 있음) -> 스코프 체인 (Scope Chain)이 포함되기도 함: 현재 컨텍스트의 변수 객체와 상위 컨텍스트들의 변수 객체 목록
    c) this 값: 현재 컨텍스트에서의 this 키워드 값

  • 종류: 전역 실행 컨텍스트, 함수 실행 컨텍스트, eval 실행 컨텍스트, 모듈 실행 컨텍스트

  • 작동 방식: 코드 실행 시 생성되고, 함수 호출 시 새로운 컨텍스트가 생성되어 스택에 쌓인다.

2️⃣ 실행 컨텍스트(Execution Context)에 대해서 설명해주세요.
실행 컨텍스트는 실행 가능한 코드에 제공할 환경 정보를 모아놓은 객체입니다.
해당 객체에는 변수 객체, 스코프 체인, this 정보가 담겨있습니다.
자동으로 전역 컨텍스트가 생성된 후 함수 호출시마다 함수 컨텍스트가 생성되고, 컨텍스트 생성이 완료된 후에 함수가 실행됩니다. 함수 실행 중에 사용 되는 변수들을 변수 객체 안에서 값을 찾고 값이 존재하지 않는다면 Lexical 환경의 outerEnvironmentReference를 통해 Scope 체인을 따라 올라가면서 탐색합니다. 함수 실행이 마무리가 되면 해당 컨텍스트는 사라지고, 페이지가 종료되면 전역 컨텍스트도 사라집니다.

3️⃣ 렉시컬 환경이란 무엇인가요?
렉시컬 환경은 특정 코드가 선언된 환경을 의미하는 객체입니다.
환경 레코드와 외부환경레퍼런스로 나뉘는데,
환경레코드에는 현재 컨텍스트와 관련된 코드의 식별자 정보가 저장됩니다. 즉, JS 엔진은 코드가 실행되기 전에 실행 컨텍스트에 속한 변수명을 모두 알고 있는 것인데요, 이를 위해 호이스팅이 발생한다고 볼 수 있습니다.
외부환경레퍼런스는 현재 호출된 함수가 선언될 당시의 렉시컬 환경을 참조하는데, 이를 이용해서 스코프 체이닝이 가능해집니다.

4️⃣ 실행 컨텍스트의 객체에 담긴 정보는 무엇이 있나요?
변수 객체, Scope 체인, this 값이 있습니다.
변수 객체에는 변수, 매개변수parameter, 인수argument 정보와 함수 정보가 담겨있고, 이때 변수와 함수 표현식으로 생성된 함수는 생성은 되지만 초기화는 되지 않아 undefined 상태입니다.
스코프 체인은 연결리스트 형태로 스코프 정보가 저장된 것이고,
this 값에는 이 변수 객체의 this에 바인딩 할 객체를 저장합니다.

Closure 클로저

1️⃣ 클로저란 무엇인가요?
클로저란 어떤 외부 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상이라고 정의할 수 있을 것 같습니다.
함수의 렉시컬 환경은 호출 시점이 아닌 정의 시점에 정해집니다. 그래서 클로저 함수의 경우 외부 함수의 실행이 종료된 후에도 외부 함수의 스코프, 즉 함수가 선언된 렉시컬 환경에 접근하여 내부 식별자를 변경할 수도 있다는 특성을 가집니다.
일반적으로 (1) 상위 스코프의 식별자를 참조하고 있고 (2) 외부 함수보다 생명주기가 더 오래 유지되는 경우를 클로저라고 말합니다.

2️⃣ 클로저의 원리는 무엇이고, 왜 사용하나요?
클로저는 내부 함수를 외부로 반환하는 함수가 있을 때, 해당 함수가 실행 종료가 되어도 내부 함수에 의해 그 렉시컬 환경이 호출될 수 있는 현상입니다.
이는 함수의 (1) 렉시컬 환경이 호출 시점이 아닌 정의되는 시점에서 정해진다는 것과 (2) 가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 그 값을 수집 대상에 포함시키지 않기 때문에 발생하는 현상입니다.
클로저는
1. 상태를 안전하게 은닉해서 특정 함수에게만 상태 변경을 허용하게 할 때
2. 클로저를 사용하면 전역 변수를 줄일 수 있는데, 이런 방식을 이용하여 함수형 프로그래밍에서 Side Effect를 최대한 억제하여 오류를 피하고 프로그램의 안정성을 높이고자 할 때
사용합니다.

스코프는 변수나 함수의 유효 범위를 결정하며, 전역 스코프와 지역 스코프로 구분된다.

스코프 체인은 중첩된 함수들의 스코프가 계층적으로 연결된 구조로, 변수 참조 시 상위 스코프로 올라가며 검색한다.

자바스크립트는 렉시컬 스코프를 따르며, 함수는 생성 시 상위 스코프의 참조를 내부 슬롯에 저장한다.

클로저는 외부 함수의 생명주기가 끝난 후에도 내부 함수가 외부 함수의 변수를 참조할 수 있는 현상이다.

클로저는 상태를 안전하게 은닉하고 특정 함수에만 상태 변경을 허용하기 위해 사용된다.

객체

  • 객체 생성자
  • 객체 리터럴(대부분 사용)
  • 객체 프로퍼티 (객체 속성) -> key : value (프로퍼티 타입에 제한이 없다. value는 다양한 자료형이 들어가도 상관이 없다 배열,객체, 함수 / key에는 문자열이나 숫자)

this에 대해서

1️⃣ use strict모드를 사용할 경우 this는 어떻게 되나요?
this는 객체의 프로퍼티나 메서드를 참조하기 위한 자기 참조 변수이므로
일반적으로 객체의 메서드 내부 혹은 생성자 함수 내부에서만 의미가 있습니다.
strict mode가 적용된 일반 함수 내부의 this에는 undefined가 바인딩 된다.

2️⃣ 자바스크립트에서 this는 몇가지로 추론 될 수 있나요? 아는대로 말해주세요
(1) 일반 함수로 호출된 모든 함수 내부의 this는 전역 객체로 추론됩니다. 그리고 (2) 호출된 메서드나 프로토타입 메서드 내부에서는 메서드를 호출한 객체로, (3) 생성자 함수 내부에서는 생성자 함수가 생성할 인스턴스로 추론됩니다. (4) prototype의 call, apply, bind 함수를 사용하면 해당 함수의 인자로 전달된 객체를 this로 바인딩하게 되고, (5) strict 모드에서 일반 함수로 사용한 경우 undefined로 추론될 수 있습니다. (6) eventListener 안에서는 해당 eventListener가 부착된 html 요소 즉 e.currentTarget으로 추론됩니다.

3️⃣ 일반함수의 this와 화살표 함수의 this는 어떻게 다른가요?
일반 함수의 this는 window(전역 객체)을 가리키지만 화살표 함수의 this는 언제나 상위스코프의 this를 가리킨다

  • 자바스크립트에서 'this'의 값은 함수가 호출되는 방식에 따라 결정된다.
  1. 'this'는 고정된 값이 아니며, 함수 호출 시 누가 호출했는지에 따라 변경될 수 있다.

  2. 'bind()' 메서드를 사용하여 'this'의 값을 특정 객체로 고정할 수 있다.

var value = 100;
var myObj = {
  value: 1,
  func1: function() {
    console.log(`func1's this.value: ${this.value}`);

    var func2 = function(val1, val2) {
      console.log(`func2's this.value ${this.value} and ${val1} and ${val2}`);
    }.bind(this, `param1`, `param2`);
    func2();
  }
};

myObj.func1();
// console> func1's this.value: 1
// console> func2's this.value: 1 and param1 and param2
  1. 화살표 함수에서의 'this'는 상위 스코프의 'this'를 상속받는다.

일반적으로 'this'를 사용할 때는 일반 함수를(예측가능한 this를 사용할 수 있기 때문에), 내부 함수에서는 화살표 함수를 사용하는 것이 권장된다.

참고: https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/main/JavaScript#this-%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C

자바스크립트 원시타입 ⭐️

원시타입과 객체타입은 값이 저장되거나 복사되는 과정이 서로 다르다!

  • 원시타입: 값 자체로써 변수에 저장되고 복사된다 (불변값: 메모리 값 수정X / 실제로 메모리 공간에 저장된 원본 데이터의 값은 변경되지 않는다는 의미에서 불변이다.)
  • 객체타입: 참조값을 통해 변수에 저장되고 복사된다.(가변값: 메모리 값 수정O / 여러개의 값을 저장함과 동시에 또 저장하는 값의 개수가 동적으로 막 유연하게 늘어났다가 줄어들기도 했다가 하기 때문에 별도의 메모리 공간에 보관한다. 원본데이터를 수정해버린다.)

<객체 타입의 주의사항>

1. 의도치 않게 값이 수정될 수 있다.

-> 수정되었다는 사실 자체를 모른다면 꽤나 큰 오류가 발생할 수 있다. (얕은 복사)
-> 사이드 이펙트
-> 새로운 객체를 생성하면서 내부 프로퍼티만 따로 복사해오는 방식(..o1 처럼 스프레드 연산자등을 이용해)으로 객체를 복사해 와야 한다. (깊은 복사)

2. 객체 간의 비교는 기본적으로 참조값을 기준으로 이루어진다.

-> 참조값이 아닌 프로퍼티를 기준으로 두 객체를 비교하고 싶다면?
-> JSON.stringfy() 자바스크립트 내장함수 / 객체를 문자열로 변환하는 기능 을 사용해 참조값이 아닌 프로퍼티를 기준으로 비교하도록 설정해줘야 한다.

3. 배열과 함수도 사실 객체이다.

동기와 비동기 ⭐️

1️⃣ 비동기 함수에 대해 설명해주세요.
비동기 함수란 함수의 실행 결과가 즉시 반환되지 않고, 특정 조건이 충족될 때까지 기다리는 함수입니다. 비동기 함수는 일반적으로 콜백 함수나 Promise 객체를 반환하는데요, 콜백 함수는 비동기 작업이 완료되었을 때 호출되고, Promise 객체는 비동기 작업이 성공했는지 혹은 실패했는지를 나타냅니다.
비동기 함수를 잘 사용하면 서비스의 성능과 반응성을 잘 유지할 수 있으나, 콜백 지옥이 발생할 수 있으므로 Promise의 후속 처리 메서드(then, catch, finally)나 async, await를 이용하여 적절하게 코드를 구성하는 것이 필요합니다.
여러개의 비동기 함수가 실행되면 이벤트 루프는 비동기 함수 호출을 처리하고, 비동기 함수가 완료되었을 때 콜백 함수를 호출합니다. 이벤트 루프는 실행 대기 중인 비동기 함수가 있으면 해당 함수를 호출하고, 실행이 완료될 때까지 다음 비동기 함수를 호출합니다. 즉, 여러 개의 비동기 함수가 실행될 때 이 함수는 동시에 실행되며, 이벤트 루프에 의해 비동기 함수의 실행순서가 제어된다고 할 수 있습니다.

2️⃣ async, await 사용 방법을 설명해주세요.
async/await는 ES8부터 도입되어 Promise를 기반으로 하는 비동기 처리 문법으로, 동기적인 것처럼, 가독성 좋게 비동기 처리가 가능하다는 장점이 있습니다. 함수 앞머리에 async 키워드를 써서 async 함수로 정의하고, 함수 내부에서 프로미스를 반환하는 부분 앞에 await 키워드를 사용하면 async/await를 사용할 수 있는데요, 내부 코드를 진행하다 await 키워드를 마주하면 비동기적으로 처리되는 작업이 완료될 때까지 기다렸다가 결과값을 받아 처리할 수 있고, 최종적으로는 항상 Promise 객체를 반환한다는 특징이 있습니다.

3️⃣ promise와 async/await의 차이점을 설명해주세요
Promise를 사용한 비동기 통신과 async, await를 사용한 비동기 통신의 차이를 설명해주세요.
첫 번째로는 async/await 문에서는 try...catch문으로 에러 처리가 가능하지만 Promise문은 그렇지 않다는 점입니다. 프로미스를 반환하는 비동기 함수는 명시적으로 호출이 가능해서, 호출자가 명확하기 때문에 try catch 문으로 에러를 처리할 수 있기 때문에 이것이 가능합니다. 또한, 최종적으로 catch 문에서 에러를 출력하는 Promise와 달리 쉽게 문제가 발생한 부분을 찾을 수 있다는 장점도 있습니다.
두번째는 코드 가독성 입니다. Promise는 과한 프로미스 체이닝으로 가독성이 떨어질 수 있지만 async/await는 그럴 가능성이 적고, 동기적인 순서로 코드를 쉽게 파악할 수 있습니다.

  • 동기: 여러개의 작업이 있을 때 이 작업들을 순서대로 한번에 하나씩만 처리하는 방식(프로그램의 실행 방식)

-> 여기서 작업을 직접 실행하고 또 처리해주는 역할을 하는 친구를 쓰레드라고 한다.
자바스크립트는(자바스크립트 엔진) '동기'적으로 코드를 실행한다.
-> 우리가 작성한 프로그램의 실행 흐름을 읽을 때 그냥 위에서부터 아래로 실행된다.
-> 실행 흐름을 파악하기 쉽고 용이하다는 장점이 있다.
-> 동기 방식의 치명적인 단점: 만약 하나의 작업이 막 10초 정도 이렇게 아주 오래 걸리는 작업이라면 그때에는 이 쓰레드가 10초 걸리는 작업을 처리하기 전까지는 다음 작업을 진행할 수 없기 때문에 결국 전체 프로그램의 성능이 악화되어 버린다.
-> 개선 방식: 멀티쓰레드(자바나 C#에서 사용)
여러개의 쓰레드를 동시에 사용하는 멀티쓰레드라는 기법을 활용 -> 중간에 오래 걸리는 작업이 포함되어 있다고 하더라도 해당 작업이 전체 프로그램의 성능을 악화시키는 데에 별로 큰 영향을 주지 못한다.

-> 하지만 자바스크립트 엔진에는 쓰레드가 1개밖에 없다. 멀티쓰레드 방식으로는 문제를 해결할 수 없기에 '비동기'라는 방식을 통해서 문제를 해결한다.

  • 비동기: 동기적이지 않다는 뜻 / 작업을 순서대로 처리하지 않음
    앞선 작업이 종료되지 않아도 기다릴 필요 없이 다른 작업을 동시에 진행시키는 게 가능하다.
    다음 작업을 동시에 실행시킬 수 있기 때문에 단점 보완이 가능하다.
    그리고 이때 각각의 작업들이 종료되었을 때 해당 작업의 결과값을 이용해서 또 다른 동작을 수행시켜줘야 된다면 자바스크립트에서는 각각의 작업에 콜백함수를 붙여서 처리해주는 것도 가능하다.

  • setTimeout(()=>{},3000): 비동기적으로 작동하는 특수한 함수 / 코드를 특정시간이 지난 이후에 비동기적으로 실행시켜주는 기능 / 두번째 인수로 전달한 숫자 값(3초)에 해당하는 밀리세컨즈만큼 대기했다가 그 시간이 지나면 첫번째 인수로 전달한 콜백함수를 실행시켜주게 된다.
    -> 비동기 작업들은 사실 자바스크립트 엔진에 있는 스레드가 실행하는 것이 아니라 Web APIs라는 브라우저가 직접 관리하는 별도의 공간에서 따로 실행됨
    Web APIs에서 실제로 자바스크립트의 비동기 작업들이 실행된다.

    자바스크립트 엔진은 코드를 한줄씩 실행하다가 setTimeout과 같은 비동기 함수를 만나게 되면
    이 비동기 작업을 브라우저의 Web APIs에게 실행해 달라고 부탁한다. 그러면서 타이머가 끝나면 실행할 콜백 함수까지 같이 넘겨준다. 그러고나서 자바스크립트 엔진은 이 타이머를 기다리지 않고 그 아래에 있는 작업을 즉시 이어서 실행을 합니다. 그러고 이 Web APIs에 있는 이 타이머가 완료 되면 Web APIs가 전달받았던 이 콜백 함수를 다시 자바스크립트 엔진에게 돌려줍니다. 그럼 이제 자바스크립트 엔진이 돌려받은 콜백함수를 실행시킴으로써 비동기 처리가 이루어지게 된다.

-> 이러한 이유로 자바스크립트는 스레드가 하나밖에 없음에도 여러 개의 작업을 동시에 처리할 수 있다.

콜백지옥

비동기 작업의 결과를 콜백함수로 처리할 수 있는데 어떤 비동기 작업의 결과를 또 다른 비동기 작업의 인수로 넣어주는 이러한 코드가 계속 작성된다면 인덴트(들여쓰기)가 계속 깊어지는 형태로 코드가 진화하게 될 것이다.

-> 기능이 늘어날수록 가독성이 안 좋아질 것이다.

콜백지옥을 피하기 위해 Promise 비동기 작업

1️⃣ 콜백 지옥(Callback hell)을 해결하는 방법을 말씀해주세요.
콜백 지옥이란 콜백 함수에 대한 후속 처리를 위해 콜백 함수가 중첩되어 그 복잡도가 높아지는 현상을 말하는데요,
일반적으로 이 콜백 지옥을 해결하기 위해서는 ES6부터 추가된 Promise를 사용합니다. Promise는 인수로 콜백함수를 전달받고 이 속에서 비동기처리를 수행합니다. 이때 비동기 처리가 성공하면 콜백함수의 인수로 전달받은 resolve를, 실패하면 reject 함수를 호출하고, 후속 처리 메소드를 통한 에러 처리도 가능합니다.
또한 가독성을 위해 Promise와 함께 ES2017에 추가된 async, await를 함께 사용하기도 합니다.

2️⃣ Promise와 Callback 차이를 설명해주세요.
Callback 함수는 내부의 비동기로 동작하는 코드 완료를 기다리지 않고 종료되어 로직 바깥에서는 결과 값을 사용할 수가 없는 등 의도대로 동작하지 않는 부분이 있습니다. 하지만 Promise는 비동기 로직에서 처리된 결과값이 Promise 객체에 저장되기 때문에 로직 밖에서도 사용이 가능합니다.
또한 Callback 함수는 비동기의 결과를 이용하기 위해서라면 함수 내부에서 중첩 호출되어야 하므로 가독성이 떨어지지만 Promise 함수는 정적 메서드를 통해 가독성을 높일 수 있습니다.

  • Promise: 마치 날짜를 저장하는 Date 객체처럼 특수한 목적을 위해서 존재하는 자바스크립트의 내장 객체
    비동기 작업을 효율적으로 처리할 수 있도록 도와주는 자바스크립트의 내장 객체
    Promise는 setTimeout과 같은 비동기 작업을 감싸는 객체이다. 비동기 작업을 처리하는 데 필요한 거의 모든 기능을 제공해주는 객체 Promise의 3가지 상태: 대기(Pending:유튜브 영상 로딩중)
    -> 해결(resolve함수: 영상로딩 완료) -> 성공(Fulfilled : 시청가능 )
    -> 거부(reject함수: 영상 로딩 실패) -> 실패(Rejected : 시청 불가능)
    비동기 작업을 실행하는 함수: Executor
    resolve 함수를 호출 -> 이 프로미스의 비동기 작업 성공
    reject 함수를 호출 -> 이 프로미스의 비동기 작업 실패
    resolve, reject 함수 모두 인수로 프로미스의 결과 값을 전달해 줄 수 있다.
    -> then 메서드를 이용(비동기 작업이 성공했을때만)하면 프로미스로 관리하는 비동기 작업의 결과 값을 언제든지 자유롭게 불러다가 이용할 수 있다. / catch(비동기 작업이 실패했을 때) 결과 값 제공
    -> then과 catch를 연달아서 사용할 수 있는데 이렇게 사용하는 문법을 마치 체이닝 하는 것 같다라고 해서 Promise Chaining이라고 표현한다.

프로미스가 콜백지옥을 방지하기 위한 기능으로 then 메서드 안에서 새로운 프로미스 객체를 반환해주면 새로운 프로미스 객체가 then 메서드의 결과값이 된다.

Async & Await ⭐️

Async: 어떤 함수를 비동기 함수로 만들어주는 키워드, 함수가 프로미스를 반환하도록 변환해주는 키워드(프로미스를 반환하지 않는 함수에 붙여서 자동으로 해당 함수를 비동기로 작동하도록 변환하는 기능)

Await: Async 함수 내부에서만 사용이 가능한 키워드, 비동기 함수가 다 처리되기를 기다리는 역할

await을 사용하면 비동기로 작동하는 함수의 결과값을 마치 동기로 작동하는 함수처럼 받아보는게 가능하다.
따라서 API를 호출하여 서버에서 데이터를 불러온다던가 하는 비동기 작업을 마치 동기처럼 작동시킬 수 있어서 코드의 흐름을 순차적으로 읽도록 만들 수 있어, 가독성을 크게 향상시킬 수 있다는 장점을 가질 수 있다. (then 메서드를 쓰지 않아도 된다.)

async function fetchData() {
  try {
    // 서버로부터 데이터를 요청하고 응답을 기다림
    const response = await fetch('https://api.example.com/data');
    // 응답 본문을 JSON 형태로 변환하고 기다림
    const data = await response.json();
    // 데이터 출력
    console.log(data);
  } catch (error) {
    // 에러 처리
    console.error('데이터를 불러오는데 실패했습니다:', error);
  }
}

// fetchData 함수 호출
fetchData();

만약 await을 사용하지 않고 위 코드와 동일한 기능을 하는 코드를 작성해야 한다면 다음과 같이 작성해야 한다.

function fetchData() {
  // 서버로부터 데이터를 요청하고, Promise 객체 반환
  fetch('https://api.example.com/data')
    .then(response => {
      // 응답을 JSON 형태로 변환하는 Promise 반환
      return response.json();
    })
    .then(data => {
      // 변환된 데이터 출력
      console.log(data);
    })
    .catch(error => {
      // 에러 처리
      console.error('데이터를 불러오는데 실패했습니다:', error);
    });
}

// fetchData 함수 호출
fetchData();

-> 예외처리의 까다로운 점??

📌 async/await에서의 에러 처리
try...catch 문 사용 🆗
프로미스를 반환하는 비동기 함수는 명시적으로 호출할 수 있기 때문에 호출자가 명확하기 때문이다.
(원래)비동기 함수의 콜백 함수 호출 주체 != 비동기 함수 ➡️ try...catch 문으로 에러 캐치 ❌
네트워크 에러 캐치 🆗
함수 내에서 처리되지 않은 에러는 reject되어 프로미스로 반환

웹브라우저에 www.google.com을 치고 엔터를 누르면 일어나는 일

1️⃣ 주소창에 www.google.com을 입력하면 일어나는 일은 무엇인가요?
사용자가 주소창에 주소를 입력하면 먼저 브라우저가 통신을 위한 ip 주소를 파악하기 시작합니다. 이를 위해 캐싱된 DNS 기록에서 해당 도메인 주소와 대응하는 ip를 계속 탐색하는데요, 브라우저 캐시, OS 캐시, 라우터 캐시, ISP 캐시를 차례대로 확인합니다.
모든 캐시에 요청한 URL이 없는 경우 ISP의 DNS 서버가 DNS recursor로서 recursive search를 통해 해당 도메인 서버의 올바른 ip 주소를 반환합니다.
그리고 통신을 요청하고, 통신 요청에 대한 답을 보내고, 해당 답에 대한 답을 주고받는 3-Way handshaking 과정을 거쳐 브라우저와 서버가 TCP 통신을 시작하게 됩니다.
이후에는 GET이나 POST 등의 요청을 통해 브라우저가 서버에게 HTTP request를 보냅니다. 해당 요청을 서버가 받으면 request handler가 요청과 요청의 헤더, 쿠키 등을 확인하여 자세한 내용을 확인합니다. 이후 JSON이나 XML 등 특정한 포맷으로 작성한 response를 브라우저에 응답으로 보냅니다.
이를 받은 브라우저는 응답을 파싱하여 콘텐츠를 사용자에게 보여줍니다.

profile
Junior Developer 개발 기술 정리 블로그

0개의 댓글