본문 바로가기

JS

JS #16- 웹 API 6 비동기통신 (promise)

동기 / 비동기

 

동기적 통신 : 내가 하나의 데이터만 필요하더라도, 모~든 데이터가 동기적으로 통신되는 것

모든 데이터가 다시 들어오니까, 모든 화면을 브라우저가 다시 그려야한다. 

 

비동기적 통신 : 필요한 데이터에 대해서만 JSON 파일로 주고받으며 서버와 통신한다. 

 = '문자화' 시켜준다. 

 

 

 

통신 오류 메세지

 

 

비동기 통신 API 

 

 

 

 

body를 직접 실어서 보내줘야지 실행할 수 있다.

확장프로그램 thunder를 다운받아서 get 주소에 넣고 send

const xhr = new XMLHttpRequest();
xhr.open('GET', END_POINT) //통신방식, 통신할 대상 , POST할때는 body를 함께 전달

ㄴ POST형식으로 받을 때는 body를 함께 전달해야한다. 

 

 

 XMLHttpRequest

 

 
import {} from './lib/index.js';




//xmlhttprequest

const xhr = new XMLHttpRequest();
xhr.open('GET', END_POINT) //통신방식, 통신할 대상


xhr.addEventListener('readystatechange', () => {
    if(xhr.status >= 200 && xhr.status < 400){
        console.log('통신 성공!');
    }else {
        console.log('통신 실패!');
    }
})


xhr.send();

 

 

 

콜백함수 
  • parse -> json을 js객체로
  • stringify() -> js객체를 json으로
  • readtState ===4 : 데이터를 다 받았다는 

function xhr(method, url) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', END_POINT) //통신방식, 통신할 대상 , POST할때는 body를 함께 전달
   
   
    xhr.addEventListener('readystatechange', () => {
       
        const {readyState, status, response} = xhr;
   
        if(readyState === 4){
            if(xhr.status >= 200 && xhr.status < 400){
                console.log(xhr.response);
                JSON.parse(response); //이걸 밖에 어떻게 끌어와서 쓸 수 있을까?
            }else {
                console.log('통신 실패!');
            }
        }
    })
   
   
    xhr.send(JSON.stringify());

}


xhr('GET, END_POINT')

JSON.parse를 밖에 꺼내와서 쓰고싶으면 어떻게 해야할까? 

=> 콜백함수로 함수를 던져서, 성공 시 실행하도록한다. 

 

 

function xhr(method, url, success) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', END_POINT) //통신방식, 통신할 대상 , POST할때는 body를 함께 전달
   
   
    xhr.addEventListener('readystatechange', () => {
       
        const {readyState, status, response} = xhr;
   
        if(readyState === 4){
            if(xhr.status >= 200 && xhr.status < 400){ //200은성공
                console.log(xhr.response);
               
                success(JSON.parse(response));//여기서 수행을 한다.
           
            }else {
                console.log('통신 실패!');
            }
        }
    })
    xhr.send(JSON.stringify());
}


xhr('GET, END_POINT',(data)=>{console.log(data)}) //함수를 세번쨰 인자로 넘긴다1
function xhr(obj) {
    const {method = 'GET', url = '', onSuccess = null, onFail = null, body = null} = obj;
   //구조분해할당 하면서 기본값까지 정의
   
    const xhr = new XMLHttpRequest();

    xhr.open(method, url) //통신방식, 통신할 대상 , POST할때는 body를 함께 전달
   
    xhr.addEventListener('readystatechange', () => {
       
        const {readyState, status, response} = xhr;
   
        if(readyState === 4){
            if(xhr.status >= 200 && xhr.status < 400){ //200은성공
                console.log(xhr.response);
               
                onSuccess(JSON.parse(response)); //여기서 수행을 한다.
           
            }else {
                onFail({message: '에러가 발생했습니다.'})
                console.log('통신 실패!');
            }
        }
    })
   
   
    xhr.send(JSON.stringify(body));

}


// xhr('GET',
// END_POINT,
// (data)=>{console.log(data)},
// ({message})=> {console.log(message)},
// {name : 'tiger'}
// ); //인자가 너무 많아서 어렵다.


xhr({ //객체로 넘기면 편하다.
    method:'POST',
    url:END_POINT,
    onSuccess(data){console.log(data)},
    onFail(){ },
    body:{name:'tiger'}
  });

ㄴ 객체로 받기

 

post 방식
import {} from './lib/index.js';




//xmlhttprequest


function xhr({ //xhr 함수 정의 매개변수 / 본문
    method = "GET",
    url = "",
    onSuccess = null,
    onFail = null,
    body = null,
    headers = {
        'Content-Type' : 'application/json',
        'Access-Control-Allow-Origin' : '*' //모든 것을 받겠다. 는 뜻! 선택를 했더라도, 백엔드단에서 허용하지 않을 수 있다.
    }
}){
    const xhr = new XMLHttpRequest();

    xhr.open(method, url) //통신방식, 통신할 대상 , POST할때는 body를 함께 전달
   
    Object.entries(headers).forEach(([key, value])=>{
        xhr.setRequestHeader(key,value);
    })
   
   
    xhr.setRequestHeader('Content-Type', 'application/json'); //header 를 정의 (개발자도구 > 네트워크 > users)

    xhr.addEventListener('readystatechange', () => {

        const {readyState, status, response} = xhr;

        if(readyState === 4){
             if(xhr.status >= 200 && xhr.status < 400){ //200은성공
                console.log(xhr.response);
               
                 onSuccess(JSON.parse(response)); //여기서 수행을 한다.
           
            }else {
                onFail({message: '에러가 발생했습니다.'})
                console.log('통신 실패!');
            }
        }
    })

    xhr.send(JSON.stringify(body));
}




xhr({ //객체로 넘기면 편하다.
    method:'POST',
    url:END_POINT,
    onSuccess(data){console.log(data)},
    onFail(){ },
    body:{name:'tiger'}
  });

 

 

 

 


 

자바스크립트 함수는 객체이다!

객체에서는 메서드를 정의해서 사용할 수 있다.

즉, xhr.get() / xhr.post() / xhr.delete() 와 같은 메서드의 형태로 비동기 통신을 정의하여 사용할 수가 있다. 

ㄴ j.query를 쓰면 이미 정의된 메서드로도 사용 가능! 

 

 

콜백 지옥
const first = getNode('.first');
const second = getNode('.second');


function delay(callback, timeout = 1000) {
    setTimeout(callback, timeout)

}

delay(()=> {
    first.style.top = ' -100px'
    delay(()=> {
        first.style.transform = 'rotate(360deg)'

        delay(()=> {
            first.style.top = '0';
            second.style.top = '0';
        })
        second.style.transform = 'rotate(-360deg)'
    })
    second.style.top = ' 100px'
})


애니메이션을 차례로 처리해주고자 할 때 delay라는 함수를 계속해서 만들어줘야해서 콜백 지옥에 빠질 수 있다! 

 

 

--> 이를 해결하기 위해서는 'promise' 가 필요하다! 

 

 

 

 

 


 

 

 

promise

기본 형태

resolve와 rejcet의 순서는 헷갈려서는 안된다!

 

 

 

promise객체의 메서드

then, catch, finally

then
function delayP(){

    return new Promise((resolve,reject)=>{

        setTimeout(()=> {
            resolve('성공~');
        }, 3000);
    })
}

const result = delayP();
result.then((res)=>{
    console.log(res);
})

console.log();

promise 문 안에 setTimeout을 쓰는 이유는, 비동기 통신 환경과 동일하게 만들기 위해서 사용했다.

비어있는 promise 객체를 반환한다. 

 

 

result를 불러온 다음에, 처리, 다음에, 처리

ㄴ 이러한 모습이 마치 콜백함수의 처리 방식과 동일하다! 

 

 

catch

function delayP(){

    return new Promise((resolve,reject)=>{

        setTimeout(()=> {
            // resolve('성공~');
            reject('실패 ㅠㅠ');
        }, 2000);
    })
}

const result = delayP();
result
.then((res)=>{
    console.log(res);
})
.catch((err)=>{
    console.log(err);
})

promise가 reject된 경우에는 에러를 잡을 수 있다. 

이 에러를 잡기 위해서 catch 메서드를 이용해서 err 객체를 보여줄 수 있다. 

 

 

catch 절을 쓰지 않고도 에러를 잡을 수 있다 ?!!

=> then은 두번째 매개변수를 받을 수있는데 (첫번째 : 성공 / 두번째 : 실패) 


function delayP(){

    return new Promise((resolve,reject)=>{

        setTimeout(()=> {
            // resolve('성공~');
            reject('실패 ㅠㅠ');
        }, 2000);
    })
}

const result = delayP();
result
.then((res)=>{
    console.log(res);
},
(err)=> {
    console.log(err);
}
)

 

 

 

Promise 를 이용하여 비동기 통신 진행하기! 
ㄴ 훨씬 더 쉽게 해결해줄 수 있다. 

 


function xhrPromise(method,url,body){


    const xhr = new XMLHttpRequest();
 
    xhr.open(method,url);
 
    xhr.send(JSON.stringify(body));
 
   
    return new Promise((resolve, reject) => {
      xhr.addEventListener('readystatechange',()=>{
        if(xhr.readyState === 4){
          if(xhr.status >= 200 && xhr.status < 400){
            resolve(JSON.parse(xhr.response)) //성공 시 resolve
           
          }else{
            reject() //실패 시 reject
            // error
          }
        }
      })
    })
  }
 
 
 
  xhrPromise('GET',END_POINT)
  .then((res)=> {
    console.log(res);
  })
  .catch((err)=> {
    err.message
  })

 

 

 

await

1. promise 객체의 데이터를 받아온다. 

2. promise 작업이 끝날 떄까지 아래 코드를 실행하지 않고 기다린다! 

3. async 함수일 때에만 await을 사용할 수 있다. 

async 함수는 항상 promise를 반환한다.