Posts JavaScript - 자바스크립트 fetch와 async/await
Post
Cancel

JavaScript - 자바스크립트 fetch와 async/await


JavaScript - 자바스크립트 fetch와 async/await


🚀 자바스크립트 fetch API

자바스크립트에서는 fetch로 리소스를 비동기 요청을 할 수 있습니다. 주로 API를 호출하고 응답 데이터를 받아오는 데에 주로 사용합니다.

REST API 리소스 샘플을 제공하는 https://jsonplaceholder.typicode.com/posts 을 사용해 보겠습니다.

1
2
3
4
5
6
7
fetch("https://jsonplaceholder.typicode.com/posts")
.then(function(res){
  return res.json();
})
.then(function(json){
  console.log(json);
});
  • fetch 에는 기본적으로 첫 번째 인자에 요청할 url이 들어갑니다. default로 http 메소드 중 GET으로 동작합니다.
  • 호출 시 해당 주소에 요청을 보낸 다음, 응답 객체(object Response)를 받습니다. 첫 번째 then에서 그 응답을 받고 .json() 메서드로 파싱한 json 값을 리턴합니다.
  • 그러면 그 다음 then에서 리턴받은 json 값을 받고, 원하는 처리를 할 수 있습니다.

위 코드를 ES6 문법에서 도입된 화살표 함수로 간소화하면 다음과 같습니다.

1
2
3
fetch("https://jsonplaceholder.typicode.com/posts")
.then(res => res.json())
.then(json => console.log(json));

화살표 함수 문법의 경우 첫번째 then처럼 body 부분이 단 한줄일 경우 { } 를 생략하며 => 다음에 쓴 값 자체가 리턴 됩니다.


다음과 같이 API 호출을 통해 리소스를 받고 그 값으로 어떤 변수를 초기화해야 하는 경우가 있다고 가정해 보겠습니다.

1
2
3
4
5
6
7
var text = "";
fetch("https://jsonplaceholder.typicode.com/posts")
.then(res => res.json())
.then(json => {
   text = json;
});
console.log(text); // ""

fetch가 비동기 작업을 담당하는 것에 유의한다면, 호출을 통해 응답 데이터 및 json 값 대입 전에 이미 console.log(text) 가 먼저 호출되고, 따라서 빈 문자열만이 콘솔에 출력될 것입니다.

비동기 처리라는 것은 쉽게 말하자면 시간이 소요되는 작업이 완료될 때까지 계속 기다리지 않고 따로 처리하며, 일단 다른 코드들도 먼저 실행할 수 있게끔 하는 작업이기 때문입니다. 그러므로 위처럼 순서가 정확히 보장되지 못하는 상황에 처할 수 있게 되는 것입니다.

그러므로 비동기 처리로 얻은 데이터를 이용해야 하는 부분이 있을 경우, 비동기 처리가 모두 완료된 뒤에 변수 등 초기화 작업을 진행하는 등 비동기 작업의 흐름을 제어해야 할 것입니다.


  • 일반적으로 알려진 callback 함수 를 사용한 비동기 작업 처리를 하자면 다음과 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
function getTitle(callback){
  var text = "";
  fetch("https://jsonplaceholder.typicode.com/posts")
  .then(res => res.json())
  .then(json => callback(json));
}

function callBackFunc(data){
  text = data[0].title;
  console.log(text);
}

getTitle(callBackFunc);

그런데 위에서 callBackFunc 함수에는 text 라는 변수가 선언된 적이 없는데도 거기에 값을 대입하고 있습니다. 어떻게 가능한 일일까요? 바로 클로저에 해답이 있습니다.

이 코드에서 한 가지 짚을 수 있는 부분은 콜백함수클로저로 사용되었다는 것입니다.

자바스크립트 클로저 : https://chanhuiseok.github.io/posts/js-5/

즉, getTitle이라는 외부 함수 내부에 callback 이라는 내부 함수가 리턴되고 있는데 이 함수는 외부 함수의 자유변수인 text를 여전히 참조할 수 있습니다. 따라서 콜백함수에서는 getTitle 의 변수 text에 응답받은 데이터를 넣은 것이며, 이것을 콘솔에 출력하고 있는 것입니다.


  • async/await 을 사용하여 좀 더 코드를 간단히 작성해 보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getTitle(){
  const response = fetch("https://jsonplaceholder.typicode.com/posts");
  return response.then(res => res.json());
}

async function exec(){
  var text;
  try {
    text = await getTitle();
    console.log(text[0].title);
  }
  catch(error){
    console.log(error);
  }
}

exec();

getTitle 함수는 fetch를 통해 호출한 API로부터 응답 데이터 받고 JSON 파싱하여 리턴하는 부분만 담당합니다. 그리고 그 데이터를 받아서 처리하는 함수가 exec 입니다.

이 때, await비동기 작업의 결과값을 얻을 때까지 기다려 줍니다. 그리고 getTitle 함수로부터 정상적으로 값을 받은 다음, token 변수에 그 값을 저장하고 있습니다.

  • await 는 Promise 객체를 리턴하는 부분 앞에만 붙일 수 있습니다. 이 때, fetch API를 통해 받은 response 데이터는 Promise 객체라서 사용이 가능합니다.

  • 또한 await를 함수 내에서 사용하려면 그 함수에는 반드시 async 키워드가 붙어 있어야 합니다.

이 점에 유의한다면, 콜백 함수를 작성할 필요 없이 거의 동기식 코드를 짜는 것처럼 작성할 수 있습니다.


참고로 async 가 붙은 함수는 항상 리턴값이 Promise가 됩니다. 따라서 아래와 같은 코드도 가능합니다.

1
2
3
4
5
6
7
8
async function getTitle(){
  const response = fetch("https://jsonplaceholder.typicode.com/posts");
  return response;
}

getTitle()
.then(res => res.json())
.then(json => console.log(json));

getTitle 함수가 리턴하는 response는 프로미스 객체가 되므로 then을 사용하여 값을 처리할 수 있습니다.


만약 콜백함수로 이전 비동기 작업으로부터 처리 완료한 값을 받고, 다음 작업들을 처리할 경우 자칫하면 콜백 지옥에 빠질 수도 있습니다. (어떤 비동기 처리 이후 그 결과를 받고 매개변수로 넘겨진 콜백함수에 그 값이 전달되고, 다시 거기서 비동기 처리 이후 그 결과를 다음 콜백 함수에 전달되고, …) 콜백 지옥은 개수가 많아질수록 코드가 보기 힘들어지는 단점이 존재합니다.

따라서 async/await는 여러 API를 호출하여 그 값들을 이용해야 할 때 진가를 발휘할 수 있습니다.


참고 : Online JavaScript Editor (playcode.io) 에서는 자바스크립트 코드를 작성한 후, 온라인에서 손쉽게 실행하고 결과를 확인할 수 있습니다.