JavaScript

프로미스

Hun-bot 2022. 7. 11. 21:54
728x90
반응형

비동기 처리를 위한 콜백 패턴

콜벡 헬

비동기+비동기+비동기.... (에러 ????? / 가독성 ↓)

비동기 함수를 호출하면 함수 내부의 비동기로 동작하는 코드가 완료되지 않았다 해도 기다리지 않고 즉시 종료된다

즉, 비동기 함수 내부의 비동기로 동작하는 코드는 비동기 함수가 종료된 이후에 완료된다.

따라서 비동기 함수 내부의 비동기로 동작하는 코드에서 처리 결과를 외부로 반환하거나 상위 스코프의 변수에 할당하면 기대한 대로 동작하지 않는다

ex)setTimeOut

let g=0;

setTimeout(()=>{g=100},0)
console.log(g) //0

onload는 비동기

let toods;

const get=url=>{
  const xhr=new XMLHttpRequest();
  xhr.open('GET',url)
  xhr.send()

  xhr.onload=()=>{
    if(xhr.status===200){
      return JSON.parse(xhr.response)
      // todos=JSON.parse(xhr.response)
    }
    console.error(`${xhr.status} ${xhr.statusText}`)
  }
}

const res=get('https://jsonplaceholder.typicode.com/posts/1')
console.log(res); //undefined

//log(todos) // undefined

그냥 return 시키나 상위 스코프 변수에 할당하더라도 원하는 값이 나오지 않는다

xhr.onload 이벤트 핸들러는 load 이벤트 발생시 일단 태스크 큐에 저장되어 대기 -> 콜 스택이 비었을때 이벤트 루프에

의해 콜 스택으로 푸시되어 실행

-> onload 이벤트 핸들러가 실행되는 시점의 콜 스택은 비어있어야 한다 따라서 console.log는 이미 종료된 이후

onload 이벤트 핸들러가 상위 스코프 변수에 할당하기 전에 log가 먼저 호출되어서 undefined가 나온다

 

프로미스

비동기 처리 상태와 처리 결과를 관리하는 객체

const promiseGet=url=>{
  return new Promise((resolve,reject)=>{
    const xhr=new XMLHttpRequest();
    xhr.open('GET',url)
    xhr.send()

    xhr.onload=()=>{
      if(xhr.status===200){
        resolve(JSON.parse(xhr.response))
      }
      else{
        reject(new Error(xhr.status))
      }
    }
  })
}
promiseGet('https://jsonplaceholder.typicode.com/posts/1')
프로미스의 상태 정보 의미 상태 변경 조건
pending 비동기 처리가 아직 수행되지 않은 상태 프로미스가 생성된 직후 기본 상태
fulfilled (settled) 비동기 처리가 수행된 상태(성공) resolve
rejected (settled) 비동기 처리가 수행된 상태(실패) reject

(settled) pending이 아닌 상태로 비동기 처리가 수행된 상태

 

후속 처리 메서드

.then .catch .finally

const promiseGet=url=>{
  return new Promise((resolve,reject)=>{
    const xhr=new XMLHttpRequest();
    xhr.open('GET',url)
    xhr.send()

    xhr.onload=()=>{
      if(xhr.status===200){
        resolve(JSON.parse(xhr.response))
      }
      else{
        reject(new Error(xhr.status))
      }
    }
  })
}
promiseGet('https://jsonplaceholder.typicode.com/posts/1')
.then(res=>console.log(res))
.catch(err=>console.log(err))
.finally(()=>console.log('Done'))

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise

 

Promise - JavaScript | MDN

Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.

developer.mozilla.org

https://ko.javascript.info/promise-basics

 

프라미스

 

ko.javascript.info

자세한 메서드와 내용은 위 2사이트를 참고하길 바란다

 

마이크로태스크 큐

setTimeout(()=>console.log(1),0)

Promise.resolve()
  .then(()=>console.log(2))
  .then(()=>console.log(3))

로그의 순서를 맞춰봐라

2-> 3 -> 1 

이유 : 프로미스의 후속 처리 메서드의 콜백 함수는 태스크 큐가 아니라 마이크로태스크 큐에 저장되기 때문

이 큐에는 프로미스의 후속 처리 메서드의 콜백 함수가 일시 저장된다

 

fetch

fetch는 HTTP 응답을 나타내는 Response 객체를 래핑한 Promise 객체를 반환한다

then을 통해 프로미스가 resolve한 Response 객체를 전달받을 수 있다

const url='https://jsonplaceholder.typicode.com/todos/1'

fetch(url).then(()=>console.log('ok'))
.catch(()=>console.log('err'))

const wrongUrl='https://jsonplaceholder.typicode.com/x12sd2/1'

fetch(wrongUrl).then(()=>console.log('ok'))
.catch(()=>console.log('err'))

잘못된 URL 지정 (404 Not Found) -> err가 출력되는 것이 아닌 'ok'가 출력된다

 

fetch 함수가 반환하는 프로미스는 기본적으로 404,500같은 HTTP 에러가 발생해도 reject 하지 않고 불리언 타입의 ok 상태를 false로 설정한 Response 객체를 resolve한다

오프라인 등의 네트워크 장애나 CORS 에러에 의해 요청이 완료되지 못한 경우에만 프로미스를 reject함

 

아래처럼 명시적으로 에러처리를 해줘야함

const wrongUrl='https://jsonplaceholder.typicode.com/XXXX/1'

fetch(wrongUrl)
.then(res=>{
  if(!res.ok) throw new Error(res.statusText)
  return res.json()
})
.then(todo=>console.log(todo))
.catch(err=>console.log(err))

https://developer.mozilla.org/ko/docs/Web/API/Fetch_API/Using_Fetch

 

Fetch 사용하기 - Web API | MDN

Fetch API는 HTTP 파이프라인을 구성하는 요청과 응답 등의 요소를 JavaScript에서 접근하고 조작할 수 있는 인터페이스를 제공합니다. Fetch API가 제공하는 전역 fetch() (en-US) 메서드로 네트워크의 리소

developer.mozilla.org

const request={
  get(url){
    return fetch(url)
  },
  post(url,payload){
    return fetch(url,{
      method:'POST',
      headers:{'content-Type':'application/json'},
      body:JSON.stringify(payload)
    })
  },
  patch(url,payload){
    return fetch(url,{
      method:'PATCH',
      headers:{'content-Type':'application/json'},
      body:JSON.stringify(payload)
    })
  },
  delete(url){
    return fetch(url,{method:'DELETE'})
  }
}

 

728x90
반응형