[강의] 비동기 실행과 Promise 객체 1

김하은·2023년 11월 14일
0

코드잇 강의 정리

목록 보기
42/60
  • 웹 통신을 하는 자바스크립트 코드를 작성할 때 알아야 하는 개념과 문법들

fetch 함수와 비동기 실행

  • 왜 response보다 End가 먼저 나왔을까?
  • fetch함수에 비동기 실행이 되는 부분이 있기 때문임
  • 비동기 실행: 한번 시작된 작업이 완료되기 전에 바로 다음 코드로 실행이 넘어가고 나중에 콜백이 실행됨으로써 작업이 마무리되는 것
  • 위 코드의 실행 순서
    1. console.log('Start');
    2. fetch 함수(리퀘스트 보내기 및 콜백 등록)
    3. console.log('End');
    4. 리스폰스가 오면 2. 에서 then 메소드로 등록해뒀던 콜백 실행

동기 실행과 비동기 실행

동기 실행

  • 한번 시작한 작업은 다 처리하고 나서야, 다음 코드로 넘어가는, 우리에게 익숙한 방식의 실행

비동기 실행

  • 특정 작업을 시작(리퀘스트 보내기)하고 완벽하게 다 처리(리스폰스를 받아서 처리)하기 전에, 실행 흐름이 바로 다음 코드로 넘어가고, 나중에 콜백이 실행되는 것
  • 비동기 실행의 존재 이유: 동일한 작업을 더 빠른 시간 내에 처리할 수 있기 때문임

알아야하는 비동기 실행 함수들

setTimeout 함수

  • 특정 함수의 실행을 원하는 시간만큼 뒤로 미루기 위해 사용하는 함수
  • fetch 함수에서는 콜백이 실행되는 조건이, '리스폰스가 도착했을 때'였다면, setTimeout에서 콜백이 실행되는 조건은, '설정한 밀리세컨즈만큼의 시간이 경과했을 때'임
console.log('a');
setTimeout(() => { console.log('b'); }, 2000);
console.log('c');

setInterval 함수

  • 특정 콜백을 일정한 시간 간격으로 실행하도록 등록하는 함수
console.log('a');
setInterval(() => { console.log('b'); }, 2000);
console.log('c');

addEventListener 메소드

  • 클릭과 같은 특정 이벤트가 발생했을 때 실행할 콜백을 등록함
  • 파라미터로 전달된 콜백이 당장 실행되는 것이 아니라, 나중에 특정 조건(클릭 이벤트 발생)이 만족될 때(마다) 실행되기 때문에 비동기 실행임
...

btn.addEventListener('click', function (e) { // 해당 이벤트 객체가 파라미터 e로 넘어옵니다.
  console.log('Hello Codeit!');
});

// 또는 arrow function 형식으로 이렇게 나타낼 수도 있습니다.
btn.addEventListener('click', (e) => {
  console.log('Hello Codeit!');
});

... 

fetch 함수가 위 함수들과 다른점

  • fetch 함수는 콜백을 파라미터로 바로 전달받는 게 아니라, fetch 함수가 리턴하는 어떤 객체의 then 메소드를 사용해서 콜백을 등록함
  • fetch 함수만 형식이 다른 이유
    • 새로운 방식으로 비동기 실행을 지원하는 자바스크립트 문법과 연관이 있기 때문임
    • fetch 함수는 Promise 객체라는 것을 리턴하고, 이 Promise 객체는 비동기 실행을 지원하는 또 다른 종류의 문법에 해당함
// 위 함수들
setTimeout(콜백, 시간) 
setInterval(콜백, 시간)
addEventListener(이벤트 이름, 콜백)

// fetch 함수
fetch('https://www.google.com')
  .then((response) => response.text()) // fetch 함수가 리턴하는 객체의 then 메소드를 사용해서 콜백을 등록
  .then((result) => { console.log(result); });

fetch 함수는 Promise 객체를 리턴합니다

  • promise객체: 어떤 작업에 관한 '상태 정보'를 갖고 있는 객체
  • 3가지 상태를 가짐
  1. pending: 작업이 진행 중
  2. fulfilled: 작업이 성공적으로 완료됨
    • 프로미스 객체는 작업의 성공 결과도 함께 가짐
  3. rejected: 작업이 실패했음
    • 프로미스 객체는 작업의 실패 이유에 관한 정보를 가짐

fetch 함수를 사용한 코드, 다시 해석하기

  • then메소드: 프로미스 객체의 메소드로 프로미스 객체가 pending 상태에서 fulfilled 상태가 될 때 실행할 콜백을 등록하는 메소드
  • 프로미스 객체의 작업 성공 결과는 첫 번째 콜백의 파라미터로 넘어옴
  • response를 자바스크립트 객체로 만든 결과가 넘어옴
console.log('Start!');

fetch('https://www.google.com')
  .then((response) => response.text())
  .then((result) => { console.log(result); });

console.log('End'); 








Promise Chaining이란?

  • 프로미스 체이닝: 프로미스 객체에 then메소드를 연속적으로 붙이는 것
  • then메소드: 새로운 프로미스 객체를 리턴함
  • 위 상황에서 모든 then메소드들은 각각 별개의 프로미스 객체를 리턴함
  • 프로미스 객체의 then 메소드가 결국 또 새로운 프로미스 객체를 리턴하기 때문에 then메소드 뒤에 또 then을 붙여나갈 수 있음
  • then 메소드가 리턴한 프로미스 객체는 가장 처음에는 pending 상태임
  • 하지만 나중에 then 메소드를 등록한 콜백이 실행되고 콜백에서 어떤 값을 리턴하면 then 메소드가 리턴했던 프로미스 객체가 영향을 받음
    • 이 때 콜백에서 어떤 값을 리턴하느냐에 따라서 받는 영향이 달라짐
    1. 프로미스 객체를 리턴하는 경우: 콜백이 리턴한 프로미스 객체와 동일한 상태와 결과를 갖게 됨
    2. 프로미스 객체가 아닌 값을 리턴하는 경우: 숫자, 문자열, 일반 객체 등 / fulfilled 상태가 되고 콜백의 리턴값을 작업 성공의 결과로 갖게 됨
  • then 메소드가 리턴했던 Promise 객체(A)는 그 콜백에서 리턴한 Promise 객체(B)와 동일한 상태와 결과를 갖게 됨
    예시 JSON

text, json 메소드도 Promise 객체를 리턴해요

text 메소드

  • fetch 함수로 리스폰스를 잘 받으면, response 객체의 text 메소드는,
    • fulfilled 상태이면서
    • 리스폰스의 바디에 있는 내용을 string 타입으로 변환한 값을
    • '작업 성공 결과'로 가진
  • Promise 객체를 리턴함
  • 이때 그 값이 만약 JSON 데이터라면 이전에 배운 것처럼 Deserialize를 해줘야함(JSON.parse(result);)

json 메소드

  • fetch 함수로 리스폰스를 잘 받으면, response 객체의 json 메소드는,
    • fulfilled 상태이면서,
    • 리스폰스의 바디에 있는 JSON 데이터를 자바스크립트 객체로 Deserialize해서 생겨난 객체를
    • '작업 성공 결과'로 가진
  • Promise 객체를 리턴함
  • 만약 리스폰스의 바디에 있는 내용이 JSON 타입이 아니라면 에러가 발생하고 Promise 객체는 rejected 상태가 되면서 '작업 실패 정보'를 갖게 됨

콜백에서 리턴한 Promise 객체로부터 새로운 Chain이 시작되기 때문에 response 객체의 text 메소드 또는 json 메소드 이후에 등장하는 then 메소드부터는 string 타입의 값이나 자바스크립트 객체를 갖고 바로 원하는 작업을 할 수 있음


Promise Chaining이 필요한 경우

  • 프로미스 객체를 리턴하는 경우를 제외하고는 하나의 콜백 안에 몰아서 써도 됨
  • Promise Chaining이 필요한 경우: 비동기 작업을 순차적으로 수행해야 할 때 전체 코드를 좀 더 깔끔하게 나타내기 위해서 사용함
  • 프로미스 체이닝을 하면 순차적으로 처리해야 할 비동기 작업의 수가 아무리 많더라도 계속해서 then 메소드를 붙여나감으로써 깔끔한 코드를 작성할 수 있음


rejected 상태가 되면 실행할 콜백

  • 프로미스 객체가 rejected 상태가 됐을 때 실행할 콜백을 설정하고 싶다면 then 메소드의 두 번째 파라미터로 원하는 콜백을 넣어주면 됨
  • 프로미스 객체가 rejected 상태가 되면 해당 콜백에는 작업 실패 정보가 파라미터로 넘어옴

then 메소드 완벽하게 이해하기

const successCallback = function () { };
const errorCallback = function () { };

fetch('https://jsonplaceholder.typicode.com/users') // Promise-A
  .then(successCallback, errorCallback); // Promise-B
  • fetch 메소드가 리턴하는 Promise 객체를 Promise-A 객체
  • then 메소드가 리턴하는 Promise 객체를 Promise-B 객체
    • fetch 함수의 작업이 성공해서 Promise-A 객체가 fulfilled 상태가 된 경우 : then 메소드 안의 "첫 번째" 콜백인 successCallback이 실행됨
    • fetch 함수의 작업이 실패해서 Promise-A 객체가 rejected 상태가 된 경우 : then 메소드 안의 "두 번째" 콜백인 errorCallback이 실행됨
  • Promise-B는, 실행된 successCallback 또는 errorCallback에서 무엇을 리턴하느냐에
    • 그 상태(fulfilled or rejected)와
    • 결과(작업 성공 결과 or 작업 실패 정보)가 결정됨

1. 실행된 콜백이 어떤 값을 리턴하는 경우

(1) Promise 객체를 리턴하는 경우

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) => response.json())
  .then((result) => { console.log(result) });
  • 콜백이 리턴한 Promise 객체의 상태와 결과를 똑같이 따라 갖게 됨
  • 콜백에서 리턴한 Promise 객체로부터 다시 Promise Chain이 쭉 이어져 나간다고 보면 됨

(2) Promise 객체 이외의 값을 리턴하는 경우

// Internet Disconnected

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) => response.json(), (error) => 'Try again!')
  .then((result) => { console.log(result) });
  • fulfilled 상태가 되고 작업 성공 결과로 그 값을 갖게 됨
  • 인터넷이 안 되는 상황에서 이 코드를 실행하면 fetch 함수의 작업이 실패해서 두 번째 콜백인 (error) ⇒ 'Try again! 이 실행됨
  • 해당 콜백을 등록한 then 메소드가 리턴했던 Promise가 fulfilled 상태가 되고, 그 작업 성공 결과로 'Try again' 문자열을 갖게 됨

2. 실행된 콜백이 아무 값도 리턴하지 않는 경우

// Internet Disconnected

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) => response.json(), (error) => { alert('Try again!'); })
  .then((result) => { console.log(result) });
  • 단순히 alert 함수만 실행하고 끝나면서 이 콜백은 아무런 값도 리턴하지 않은 것과 같음
  • 자바스크립트에서는 함수가 아무것도 리턴하지 않으면 undefined를 리턴한 것으로 간주됨
  • then 메소드가 리턴했던 Promise 객체는 fulfilled 상태가 되고, 그 작업 성공 결과로 undefined를 갖게 됨

3. 실행된 콜백 내부에서 에러가 발생했을 때

// 함수 정의 안 함
fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) => { 
        ...
        add(1, 2); // ReferenceError 발생
        ... 
  });

//인위적으로 에러 발생 시킴
fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) => { 
        ...
        throw new Error('failed'); 
        ... 
  });
  • Promise 객체가 rejected 상태가 되고, 작업 실패 정보로 해당 에러 객체를 갖게 됨
  • 개발자 도구에서 promise 객체 내부를 보면 Promise 객체가 rejected 상태이고, 발생한 Error 객체를 그 작업 실패 정보로 갖고 있다는 것을 알 수 있음

4. 아무런 콜백도 실행되지 않을 때

// Internet Disconnected

fetch('https://www.google.com') // Promise-1
  .then((response) => response.text()) // Promise-2
  .then((result) => { console.log(result) }, (error) => { alert(error) }); 
  • 인터넷을 끊고 나서 위 코드를 실행하면 fetch 함수가 리턴한 Promise-1 객체는 rejected 상태가 되기 때문에, 첫 번째 then 메소드의 두 번재 콜백이 실행되어야 함
  • 그런데 지금 두 번째 콜백도 없어서 아무런 콜백도 실행되지 않는데 이런 경우에 then 메소드가 리턴한 Promise-2 객체는 이전 Promise 객체와 동일한 상태와 결과를 갖게 됨
    • Promise-2 객체는 Promise-1 객체처럼 rejected 상태가 되고, 똑같은 작업 실패 정보를 갖게 됨
  • rejected 상태가 된 Promise-2의 then 메소드에는 이제 두 번째 콜백이 존재하기 때문에 그 두 번째 콜백이 실행됨
profile
아이디어와 구현을 좋아합니다!

0개의 댓글