bdfgdfg

[Javascript] 비동기 fetch, promise, async, await 본문

웹프로그래밍/HTML_CSS_Javascript 기초

[Javascript] 비동기 fetch, promise, async, await

marmelo12 2023. 11. 4. 00:08
반응형

자바스크립트의 비동기 처리방식

자바스크립트는 기본적으로 싱글쓰레드기반의 언어.

그렇기에 비동기 작업을 요청하고, 작업이 완료되어 콜백함수등의 처리를 할 때 별도의 쓰레드가 등장해 작업을 처리하는게 아닌, 하나의 쓰레드가 모든 작업을 처리하게 된다.

 -> 요청한 비동기 작업자체는 외부에서 처리는 하지만 그 결과를 받고, 어떻게 처리할지는 자바스크립트의 쓰레드가 담당.

 -> 이는 동시성 문제를 고려하지 않아도 된다는 장점이 있음. 

 -> 또한 자바스크립트에서 비동기방식의 처리는 새로고침없이 데이터를 읽어올 수 있음.

 

 

https://chanyeong.com/blog/post/44

  • Call Stack: 자바스크립트의 쓰레드가 가진 스택영역
  • Web API: 웹 브라우저에서 제공하는 API로 AJAX나 Timeout등의 비동기 작업을 실행
  • Task Queue: Callback Queue라고도 하며 Web API에서 넘겨받은 Callback함수를 저장
  • Event Loop: 주기적으로 Call Stack을 확인하고 call stack이 비었다면 Task Queue(비동기 결과)의 작업을 Call Stack으로 옮김

위 개념의 이해와 비동기(요청한 순서대로 결과가 순차적이지x, 완료된 결과는 콜백등으로 확인, 비동기 처리 자체는 보통 외부에맡김등)의 특징을 이해한다면 fetch, promise, async, await은 간단하다.

 

Promise

Promise는 비동기 작업을 좀 더 편리하게 처리할 수 있는 문법.

-> 완료처리(콜백함수)에서 후속으로 이어지는 비동기 작업을 처리하기도 편리하다.(then)

 

보통의 비동기작업은 아래와 같은데.

// callback은 하나의 정수형 인자를 받는 함수를 받음.
function increaseAndPrint(n, callback) {
    setTimeout(() => {
        const increased = n + 1;
        console.log(increased);
        if (callback) {
            callback(increased);
        }
    }, 1000);
}  

increaseAndPrint(0, (n) => {
    increaseAndPrint(n, (n) => {
        increaseAndPrint(n, (n) => {
            increaseAndPrint(n, (n) => {
                console.log("완료");
            })
        })
    })
});

 

비동기 작업을 처리할수록 들여쓰기 레벨도 높아지며, 가독성또한 좋지않다.

Promise를 쓴다고해서 위 코드와 다르게 동작한다거나 하지는 않지만 훨씬 가독성 좋게 읽힐 수 있는 코드 작성이 가능.

 

위 코드를 Promise코드로 바꾸면 다음과 같다.

function promiseIncAndPrint(n) {
    return new Promise((resolve, reject) => {
        window.setTimeout(() => {
            const increase = n + 1;
            console.log(increase);
            resolve(increase); // resolve에는 완료된 결과를 전달가능. reject는 그 반대.
        },1000);
    })
}

promiseIncAndPrint(0)
.then((result) => {
    return promiseIncAndPrint(result);
})
.then((result) => {
    return promiseIncAndPrint(result);
})
.then((result) => {
    return promiseIncAndPrint(result);
})
.then((result) => {
    return promiseIncAndPrint(result);
})
.then((result) => {
    return promiseIncAndPrint(result);
})
.then((result) => {
    console.log("끝." + result);
})
.catch((reject) => {
    console.log("에러 : ", reject);
})

 

좀 더 깔끔한(?) 코드 작성이 가능해졌다.

결과

 

Promise에는 다음과 같은 상태가 존재하는데 비동기에 익숙하다면 항상 비슷한 용어들이니 짚고넘어가자

  • pending(대기): fulfilled(이행)도 rejected(거절)도 아닌, 작업중인 상태.
  • fulfilled(이행): 비동기 작업이 완료된 상태, 정상적인 결과값을 반환
  • rejected(실패): 비동기 작업에 실패한 상태, 에러사유를 담아서 반환.

 

그리고 then의 반환형도 Promise임.

Fetch

fetch는  HTTP 파이프라인을 구성하는 요청과 응답 등의 요소를 JavaScript에서 접근하고 조작할 수 있는 인터페이스를 제공. ajax 기법중 하나임. (ajax는 서버와 브라우저가 비동기방식으로 데이터를 교환하는 기능)

 -> 비동기 요청 API이며 반환값은 HttpResponse객체(Promise로 처리되어 resolve에 담긴값.) 그렇기에 then 체인과 묶여서 사용됨.

let url = "https://api.odcloud.kr/api/15077586/v1/centers?page=1&perPage=284&serviceKey=대충키";

// 해당 API는 요청시 Json데이터를 응답.
fetch(url)
.then(resolve => {
    return resolve.json(); // 응답데이터인 json을 js의 객체(object)로 변환.
})
.then(result => {
    result.data.forEach((data) => {
        console.log(data);
    });
})

공공기관의 코로나 예방접종센터 정보를 알 수 있는 api를 호출해서 얻어왔고 결과는 다음과 같음.

 

 

기존 제이쿼리를 사용하지않고 XMLHttpRequest객체를 통한 방법보다 훨씬 편리한 방법이라는게 장점.

 

async, await

async,await은 비동기의 결과처리인 콜백방식, Promise(fetch등)과 동일하게 비동기 결과를 어떻게 처리하는지에 관한 문법.

 -> Promise와 같이 비동기 결과 처리에 관해 가독성향상이 목적인듯한 문법.

 -> Promise를 반환해야하만 await이 정상적으로 동작한다.

function promiseRandValue() {
    return new Promise((resolve, reject) => {
        window.setTimeout(() => {
            resolve(Math.floor(Math.random() * (10) + 1)); // resolve에는 완료된 결과를 전달가능. reject는 그 반대.
        },5000);
    })
}

async function getValue() {
    let value = await promiseRandValue(); // 여기라인에서 5초를 기다렸다 다음라인실행.
    console.log(value);
}
getValue();
console.log('async함수 호출한쪽은 쭉 이어서 처리됨.');

 

위와 같이 async await을 사용하면 실제 동기방식(결과는 그자리에서 확인 및 blocking등)처럼 처리가 가능하다.

 -> 여기서 중요한건 해당 async함수내에서만 그렇게 동작한다는거다.

 -> 이건 fetch,then도 동일. fetch의 Promise결과를 then이 받아들이고, then안에서 Promise를 반환할 때 비동기 결과가 완료될 시 다음 then이 순서대로 동기방식과 같이 이어 받는것처럼.

 

사용방법은 async키워드는 function앞에 붙어서 사용되고, await키워드는 비동기 함수 앞에다 위치한다.

 -> await키워드는 비동기 함수 및 프로미스를 반환하는 함수에 위치가 가능.

 -> 또한 async키워드가 붙은 function 내부안이어야만 한다.

반응형
Comments