Promise / Async / Await + fetch 함수

Ming·2024년 3월 22일

JavaScript

목록 보기
15/15

자바스크립트는 동기식 처리라고 하는데 동기식 비동기식이 뭘까?

동기와 비동기

동기(synchronous): 순차적으로 코드 실행 O
비동기(asynchronous) : 순차적으로 코드 실행 X

자바스크립트를 실행하는 웹브라우저는 stack이라는 코드 실행공간이 있는데 거기서 코드를 차례대로 실행한다.

console.log(1)
console.log(2)
console.log(3)

위 코드는 1,2,3 순으로 출력된다. 이걸 전문용어로 동기적이다 라고 하는것
(대부분의 프로그래밍 언어들이 이렇다)

🤫그럼 자바스크립트는 동기적이기만 한가?
자바스크립트는 비동기도 가능하다! 실행이 조금 걸리는 함수는 나중에 실행해주기 때문이다.
자바스크립트를 실행하는 웹브라우저는 시간이 걸리는 특수 코드들을 발견하면 뒤로 미루고 다른 빠른 코드부터 실행하려고 한다.(자바스크립트 언어의 기능이 아니라 웹브라우저 덕분에...)

console.log(1)
setTimeout(function(){console.log(2)},1000)
console.log(3)

위 코드는 1,3이 출력되고 1초 후에 2가 출력된다. 즉 비동기적으로 처리하는것

🤫근데 비동기식 함수를 동기적으로 처리하고 싶은데...
1. 콜백함수를 사용
2. Promise 사용
3. Async 사용

동기적으로 사용하고 싶으면?

콜백함수 사용하기

: 함수안에 들어가 있는 함수

함수를 실행할때 콜백함수로 두번째 함수를 넣으면 되지 않을까?

function fn1(callback){
  console.log(1)
  callback()
}
function fn2(){
  console.log(2)
}

fn1(fn2)
// 또는
fn1(function(){fn2})

이렇게 하면 fn1이 실행되어 콘솔에 1이 찍히고 fn2가 실행되어 2가 찍힐것이다.
순서대로 처리되지만 단점은 코드가 옆으로 길어진다는 점이다
이런 콜백 패턴에서 발생하는 문제를 콜백 지옥이라고 한다.
콜백지옥은 여러모로 작성이나 해석에서 불편하다.

fn1(function(){
  fn2(function(){
    fn3(function(){
      ...
    })
  })
})

Promise 사용하기

: 콜백 패턴 대신 사용할 수 있는 문법
옆으로 길어지지 않고, 코드 실행 실패시 특정 코드를 실행할 수 있다.

Promise 사용하기

  1. new Promise() 문법으로 변수 오브젝트를 만든다.
  2. 변수에다 then()을 붙여서 실행한다.
    만약 결과를 then안에서 활용하고 싶으면 resolve의 파라미터값을 넣어주면 된다.
let 프로미스 = new Promise(function(resolve, reject){
  // 코드
  성공()
});

프로미스.then(function(){
	// 프로미스가 성공하면 코드 실행
}).catch(function(){
	// 프로미스가 실패하면 코드 실행
});
const fn1 = new Promise(resolve=>{
	let add = 1+1
    resolve(add)
});

fn1.then(function(add){
  console.log('결과는'+add)
}).catch(function(){
  console.log('실패')
})

Promise 특징

  1. new Promise()로 생성된 변수를 콘솔창에 출력해보시면 현재 상태를 알 수 있다.
    성공/실패 판정 전에는 pending
    성공 후엔 resolved 실패 후엔 rejected 이런 식으로 나온다.
    이렇게 프로미스 오브젝트들은 3개 상태가 있으며, 성공을 실패나 대기상태로 다시 되돌릴 순 없다.

아래 코드는 5초 후에 성공을 콘솔창에 찍을것이다.
1초때 콘솔창에 찍으면 pending
5초 후 콘솔창에 찍으면 resolved 가 나올것이다.

const fn1 = new Promise(function(resolve,rejected){
  setTimeout(function(){
    resolve()
  },5000)
});

fn1.then(function(add){
  console.log('성공')
}).catch(function(){
  console.log('실패')
})

console.log(fn1) // <- 5초전이면 pending
  1. 동기를 비동기적으로 만들어주는 코드는 아니다.
    Promise는 비동기적 실행과 전혀 상관이 없다.
    그냥 원래 자바스크립트는 평상시엔 동기적으로 실행되며 비동기 실행을 실행하는 특수 함수들 때문에 가끔 비동기가 되는거 뿐이다.

여러방법 사용해보기

  1. 이미지가 로딩되면 성공이라는 말을 실패하면 실패라는 단어를 콘솔에 찍어보자
let imgLoading = new Promise((resolve, reject) => {
  img.addEventListener('load',function(){
    resolve()
  })
  img.addEventListener('error',function(){
    reject()
  })
})
  
  imgLoading.then(function(){
    console.log('성공');
  }).catch(()=>{
    console.log('실패');
  })
  1. get요청이 성공하면 요청한 글 콘솔에 찍고 두번째 get요청하기
let promise2 = new Promise((resolve, reject) => {
  $.ajax({
    type : 'GET',
    url : 'https://링크'
  }).done(function(결과){
    resolve(결과);
  })
})

promise2.then(function(결과){
  console.log(결과);
  
  return new Promise((resolve2) => {
    $.ajax({
      type:'GET', url:'https://링크2'}).done(function(결과2){
      resolve2(결과2)
    })
  });
}).then(function(){
  console.log(결과2);
})

Async / Await

: Promise를 쉽게 사용할 수 있는 ES8문법
Async : function 앞에 쓰면 Promise 오브젝트가 생성되는 키워드(function앞에만 쓸 수 있음)
Await : Async 뒤쪽에 있는 함수를 기다린 다음 완료가 되면 실행시켜주는 키워드(결과를 변수에 담아 사용할 수 있음)

Async

async 키워드를 function 앞에 쓰면 Promise 오브젝트가 생성된다.
그럼 function은 promise가 되서 then 함수를 사용할 수 있다.
return을 사용해 값을 입력하면 then 함수까지 전해져서 쓸 수 있다.
단점은 늘 성공만 가능하고 실패는 강제로 해야한다

async function fn1(){ // fn1 함수 자체가 promise가 되버린다!
  return 1+1
}

fn1().then(function(add){
   console.log( add+'성공');
   })

Await

then 쓰기 싫으면 await 키워드 사용하기
async 키워드를 쓴 함수 안에서는 await을 사용할 수 있다.
또는 Promise 인스턴스가 반환이 되어야(return) 앞에 붙여 사용할 수 있다.

async function fn1(){
  var p1 = new Promise(function(성공,실패){
    var add = 1+1
    성공(add)
  })
  var 결과 = await p1; // p1이 해결될때까지 기다리고 판정이 나오면 결과를 담아줘
  console.log(결과) //2
  // 프로미스.then(function(){})과 같다
}

fn1() // 함수호출

Await은 실패하면 에러가 나고 코드가 멈춘다

async function fn1(){
  var p1 = new Promise(function(성공,실패){
    실패()
  })
  var 결과 = await p1;
  console.log(결과)
}

fn1() // 함수호출

p1 promise가 실패하면 await p1 코드는 에러가 나고 코드 실행을 멈춘다.
그럼 await 하단 코드도 실행되지 않는다.
그래서 Promise가 실패해도 코드실행을 멈추고 싶지 않을때는 특별한 방법이 필요하다.

try / catch

try : 내부의 코드 에러 판단
catch : (try내부 코드가 에러가 나면) 내부의 코드를 실행시킨다

try내부의 코드가 에러가 나야 catch안의 코드가 실행된다.

async function fn1(){
  var p1 = new Promise(function(성공,실패){
    실패(결과)
  })
  
  try{var 결과 = await p1};
  catch{console.log('실패했습니다')}
}

fn1() // 함수호출

응용

버튼을 누르면 눌렀다는 말을 콘솔에 찍어보자

async function buttonEvent(){
  button.addEventListener('click',()=>{
  return '버튼눌렀어요'
  })
}

async function buttonClick(){
  var click = await buttonEvent;
  console.log(click); // undefined
}

이렇게 하면 될거같지만 작동하지 않는다.
1. 버튼을 눌러야 이벤트 리스너 안의 코드가 실행된다.
그렇기 때문에 누르지 않았을때는 async function안의 코드는 빈칸과 동일하다.
2. 자바스크립트는 function이 빈칸이면 자동으로 return undefined를 채워 실행한다.

이럴 경우 Promise로 만들어 직접 성공(), 실패() 경우를 지정하면 await가 기다려 실행해준다

let buttonEvent = new Promise(function(성공,실패){
  button.addEventListener('click',()=>{
    성공('성공했어요')
  })
})

async function buttonClick(){
  var click = await buttonEvent;
  console.log(click); // 성공했어요
}

buttonClick()

fetch

fetch(주소,옵션)
네트워크를 통해 리소스의 요청(Request) 및 응답(Response)을 처리할 수 있다.
Promise 인스턴스를 반환한다.
(then/catch/constructor/finally 메소드 사용할 수 있다.)

요청해 응답을 받으면 응답 결과는 json 함수에 저장된다.
그래서 우리는 json메소드를 호출해야만 원하는 데이터를 꺼낼 수 있다.
❗️이 json메소드는 Promise 인스턴스를 반환한다.(then 쓸 수 있음)

예시

fetch('http://www.omdbapi.com/?apikey=####')
  .then(function(res){
  return res.json()
}).then(function(json){console.log(json)}) // 원하는 응답 결과

// 또는

const wrap = async function(){
const res = await fetch('http://www.omdbapi.com/?apikey=####')
await json = res.json()
console.log(json)
}
wrap()

옵션

객체형태로 작성할 수 있다.

fetch('http://www.omdbapi.com/?apikey=####',{
  method: 'GET', // 어떤 값을 얻어낼때 사용하는 메소드(일반적으로는 작성하지 않아도 적용)
  headers:{'Content-Type:'application/json'}, // 서버로 전송하는 요청에 대한 정보(json포멧으로 요청)
  body:JSON.stringify({name:kim , age:30}) // 요청에 대한 데이터 담아 전송(항상 json 문자화 시켜야한다)
})

0개의 댓글