데브코스 프론트엔드 5기/VanillaJS를 통한 자바스크립트 기본 역량 강화 1

231010 [Day16] VanillaJS를 통한 자바스크립트 기본 역량 강화 1 (5)

코딩하는 키티 2023. 10. 10. 23:52

Promise

  • 비동기 작업을 제어하기 위해 나온 개념으로 callback hell에서 어느정도 벗어날 수 있게 함
  • Promise로 정의된 작업끼리는 연결할 수 있고, 코드의 depth가 크게 증가하지 않게해준다

 

1) Promise 만들기

const promise = new Promise((resolve, reject) => {
  // promise 내부에서 비동기 상황 종료될 때, resolve 함수 호출
  // promise 내부에서 오류 상황일 때, reject 함수 호출
})

 

Promise에서는 then을 이용해 비동기 작업 이후 실행할 작업을 지정함

function asyncPromiseWork() {
	//code...
    
  return new Promise((resolve, reject) => {
  	//code...
    
    return resolve('complete')
  })
}

//then의 result에는 resolve를 호출하며 넘긴 complete가 들어있음
asyncPromiseWork().then(result => console.log(result))

 

Promise의 then 내에서 promise를 return할 경우 이어진다.

기존의 콜백함수를 promise 형태로 만들 수 있음

promiseWork()
	.then(result => {
    	return promiseNextWork(result)
    }).then(result => {
    	return promiseThirdWork(result)
    }).then(result => {
    	return promiseFinalWork(result)
    })

 

Promise chain 중 reject가 발생했을 경우 catch문으로 잡을 수 있다. (catch문을 안넣으면 chain이 멈춘다)

promiseWork()
	.then(result => {
    	return promiseNextWork(result)
    }).then(result => {
    	return promiseThirdWork(result)
    }).then(result => {
    	return promiseFinalWork(result)
    }).catch(e => {
    	alert('에러가 발생했군요.')
    })

 

finally에서는 성공/실패 여부 상관없이 무조건 실행

promiseWork()
	.then(result => {
    	return promiseNextWork(result)
    }).then(result => {
    	return promiseThirdWork(result)
    }).then(result => {
    	return promiseFinalWork(result)
    }).catch(e => {
    	alert('에러가 발생했군요.')
    }).finally(() => {
    	alert('작업이 끝났습니다.')
    })

 

기존의 callback 함수를 promise 형태로 만들 수 있다.

resolve를 작업이 끝나는 순간에 호출하면 된다.

const delay = (delayTime) => new Promise((resolve)
	setTimeout(resolve, delayTime)
})

delay(5000)
	.then(() => {
    	doSomething()
        retrun delay(3000)
     ).then(() => {
       console.log('complete!)
     })

강의예시 기존 콜백 -> 프로미스 변경

 

ex) 기존 request 함수 promise 형태로 바꾸기

export function request (url) {
 return new Promise((resolve, reject) => {
  const xhr = new XMLHttpRequest();
  xhr.addEventListener("load", (e) => {
    if(xhr.readyState === 4) {
      if(xhr.status === 200) {
        resolve(JSON.parse(xhr.responseText))
      } else {
        reject(xhr.statusText)
      }
    }
  })
  xhr.addEventListenr('error', (e) => reject(xhr.statusText))
  xhr.open('GET', url);
  xhr.send()
 })
}

 

 

2) 내장 함수

① Promise.all() : 배열 안 모든 promise를 처리 후 then / 여러 promise를 동시에 처리할 때 유용

const promise1 = delay(1000)
const promise2 = delay(2000)
const promise3 = delay(3000)

Promise.all([promise1, promise2, promise3]).then(() => {
})

 

② Promise.race() : 여러 promise중 하나라도 resolve/reject 되면 종료

Promise.race(iterable)

강의 예시

 

③ Promise.any(iterable) : 여러 Promise 중 하나라도 resolve 되면 종료 / reject는 무시하고, resolve 되는 것만 처리

Promise.any(iterable)

강의 예시

 

⑤ Promise.allSettled(iterable) : 여러 Promise들이 성공했거나, 실패했거나 상관없이 모두 이행된 경우 처리

 

⑥ Promise.resolve : 주어진 값으로 이행하는 Promise.then 객체를 만듦, 주어진 값이 Promise인 경우 Promise가 반환

항상 Promise를 반환해야할 때 유용하다.

 

Promise.reject : 주어진 값으로 reject 처리된 이행하는 Promise.then 객체를 만듦, 주어진 값이 Promise인 경우 Promise가 반환

 

 

 

async,  await

  • Promise를 이용해도 코드 작성에 불편함이 있어 해결하기 위해 등장
  • 동기식 코드처럼 보이는 장점이 있다. (실행은 비동기)

 

ex) then 중첩 문을 async, await 문으로 작성하기

const delay = (delayTime) => {
  return new Promise(resolve => setTimeout(resolve, delayTime));
}

const work = () => {
  console.log('work run')
  delay(1000)
    .then(() => {
      console.log('work 1 done');
      return delay(1000)
    })
    .then(() => {
      console.log('work 2 done');
      return delay(1000)
    })
    .then(() => {
      console.log('work 3 done');
      return delay(1000)
    })
    .then(() => {
      console.log('work 4 done');
      return delay(1000)
    })
}

work();
const work = async () => {
  console.log('work run') 
  await delay(1000)
  console.log('work 1 done');

  await delay(1000)
  console.log('work 2 done');

  await delay(1000)
  console.log('work 3 done');

  await delay(1000)
  console.log('work 4 done');
}

코드가 깔끔해지는 것을 볼 수 있다.

 

 

선언 방식 2가지

async function asyncFunction () {
  const res = await request(...)
}
const asyncFunction = async () {
  const res = await request(...)
}
  • async 키워드 함수가 붙은 함수는 실행결과를 Promise로 감싼다
  • 기본적으로 await는 async로 감싸진 함수 scope에서만 사용 가능했지만, top level await가 등장하여 top level에서도 사용 가능하다.

강의 예시

 

fetch

fetch api

  • 비동기 http 요청을 좀 더 편하게 해주는 API
  • XMLHTTPRequest을 대체
  • Promise 기반으로 동작

 

fetch api 사용하기

  • fetch의 기본 응답 결과는 Response 객체
  • Response 객체를 얻은 뒤엔 응답을 json이나 text로 바꾸는 처리를 해야한다.
  • json, text 외에도 다양한 method들이 있다. (blob - 이미지처리)
<html>
    <head>
        <title>kdt 4</title>
    </head>
    <body>
        <script>
        fetch('https://kdt-frontend.programmers.co.kr/todos')
        .then(res => {
            return res.json()
        })
        .then(data => {
            console.log(data)
        })
        </script>
    </body>
</html>

 

  • fetch는 HTTP error가 발생하더라도 reject 되지 않는다. 
  • 네트워크 에러나 요청이 완료되지 못한 경우에만 reject 된다.
    • => 서버 요청 중 에러가 생겼을 경우에도 then은 떨어지므로, response의 status code나 ok를 체크해주는 것이 좋다.
  • fetch의 두번째 인자로 옵션을 줄 수 있다.