오봉이와 함께하는 개발 블로그

JavaScript - 비동기 본문

FE/JavaScript

JavaScript - 비동기

오봉봉이 2023. 8. 28. 20:31
728x90

비동기

  • JavaScript를 사용하는 SPA는 JavaScript에서 제공하는 비동기 함수를 사용한다.

callback

  • JavaScript에서 함수는 객체
  • 함수의 파라미터로 함수를 전달하여 실행하는 함수를 callback 함수라고 한다.
    • 비동기성을 구현해주는 기능 자체를 callback이라 하는 것이 아니라, 비동기성을 구현하기 위해 callback을 사용하는 것
  • 비동기성 함수를 호출할 때는 제어권이 넘어가지 않지만, 동기성 함수를 호출할 때는 제어권이 넘어가게 된다.
  • 비동기 함수에 callback이 있다면, 해당 callback은 pending되어 있다가 함수가 종료되었을 때 해당 callback을 실행
  • 일반 함수에 callback을 사용하는 것은 실행 순서를 보장하는 내부 함수를 사용하는 것
  • callback의 핵심은 비동기 함수 안에 callback을 작성하여 비동기 함수가 완료될 때 callback이 정상적으로 작동하도록 하는 것
// callback 예시
function callBack_plus(num1, num2, callback) {

    callback(num1 + num2);
}

function result(result) {
    console.log("두 수의 합은 " + result + " 입니다.");
}

callBack_plus(3, 3, result);
// 비동기 callback 예시
function requestServer(callback) {
    $.get("http://www.dq.com/test.jsp?name=ktko&age=30", function(response) {
        callback(response);
    });
}

requestServer(function(result) {
    console.log(result);
});

// 잘못된 비동기 callback 예시
function requestServer() {
    var result;

    $.get("http://dq.com/test.jsp?name=ktko&age=30", function(response) {
        result = response;
    }); // 여기서 pending 되지 않고 바로 return으로 넘어가게 됨.

    return result;
}
console.log(requestServer()); //undefined

promise

  • callback과 마찬가지로 비동기 함수를 수행 시키기 위한 도구이지만, 해당 함수 안에 동기적 작업만 존재한다면 동기적으로 작동하는 함수
  • 각각의 상태를 표현할 수 있다.
    • 대기(Pending): 작업이 완료되지 않은 상태
    • 이행(Fulfilled): 작업이 성공적으로 완료된 상태 (resolve)
    • 거부(Rejected): 작업이 실패한 상태 (reject)
  • then(onFulfilled, onRejected)
    • Promise 객체의 상태가 이행됐을 때와 거부됐을 때의 처리를 정의하는 메소드.
    • 첫 번째 매개변수는 이행된 경우를 다루는 콜백 함수
    • 두 번째 매개변수는 거부된 경우를 다루는 콜백 함수
    • then을 통해서도 onRejected에 대한 처리를 할 수 있으나, catch를 통해 처리하는 것이 명확하게 눈에 들어온다.
  • catch(onRejected)
    • Promise 객체의 상태가 거부됐을 때의 처리를 정의하는 메소드
    • then() 메소드의 두 번째 매개변수로 거부 케이스를 처리하는 것과 동일한 역할
  • Promise.all(iterable)
    • 여러 개의 Promise 객체를 배열로 받아서 모든 Promise 객체가 이행될 때까지 기다린 후 결과를 배열로 반환하는 메소드
  • Promise.race(iterable)
    • 여러 개의 Promise 객체를 배열로 받아서 가장 먼저 이행된 Promise 객체의 결과를 반환하는 메소드.
  • Promise.resolve(value)
    • 이행된 Promise 객체를 반환
  • Promise.reject(reason)
    • 거부된 Promise 객체를 반환
  • then, catch를 적절하게 체이닝 방식으로 코드를 작성해서 사용할 수 있다.
    • then을 체이닝 방식을 통해 처리하기 위해서는 return을 통해 처리할 값을 반환해야 함
// 비동기 작업을 수행하는 함수를 Promise로 감싸는 예시
const fetchData = (url) => {
    return new Promise((resolve, reject) => {
        // 비동기 작업 예시: setTimeout을 사용하여 1초 후에 결과를 반환
        setTimeout(() => {
            if (url === 'https://example.com/data') {
                resolve('Data fetched successfully');
            } else {
                reject('Error fetching data');
            }
        }, 1000);
    });
};

console.log('print 1')
// Promise 사용 예시
fetchData('https://example.com/data')
    .then((result) => {
        console.log(result); // Data fetched successfully
    })
    .catch((error) => {
        console.error(error); // Error fetching data
    });
console.log('print 3')

// then에 체이닝을 통해 출력
const fetchData = (url) => {
    return new Promise((resolve, reject) => {
        // 비동기 작업 예시: setTimeout을 사용하여 1초 후에 결과를 반환
        setTimeout(() => {
            if (url === 'https://example.com/data') {
                resolve('Data fetched successfully');
            } else {
                reject('Error fetching data');
            }
        }, 1000);
    });
};

console.log('print 1')
// Promise 사용 예시
fetchData('https://example.com/data')
    .then((result) => {
        console.log(result); // Data fetched successfully
        return result + " chaining then"
    })
    .then((result) => {
        console.log(result); // Data fetched successfully chaining then
    })
    .catch((error) => {
        console.error(error); // Error fetching data
    });
console.log('print 3') 

async/await

  • 함수 앞에 async를 붙이면 해당 함수는 자동으로 Promise를 반환한다.
  • Promise로 처리되는 부분에 await을 붙이면 해당 Promise가 끝날 때 까지 기다린다.
    • 즉, 동기적으로 처리되어 Promise가 처리되면 결과와 함께 실행이 재개된다.

/* Rest API 코드
@GetMapping("/fetch/data")
public Map<String, String> responseData() throws InterruptedException {
  HashMap<String, String> data = new HashMap<>();

  data.put("data1", "DQCAT3");
  data.put("data2", "DQCAT3.1");
  data.put("data3", "LogLAY");

  Thread.sleep(3000);

  return data;
}
*/


import fetch from 'node-fetch'

function fetchApi(url) {
    return fetch(url)
        .then(response => {
            if (!response.ok) {
                throw new Error(`Network response was not ok. Status: ${response.status}`);
            }
            return response.json();
        })
        .catch(error => {
            console.error('Error fetching data:', error);
        });
}

function first () {
    console.log("This is first func")
    const apiUrl = 'http://localhost:8080/fetch/data';
    let data = {}

    fetchApi(apiUrl)
    .then(responseData => {
        data = responseData
    });
    console.log('first', data)
}

function second () {
    console.log("This is second func")
    const apiUrl = 'http://localhost:8080/fetch/data';
    let data = {}

    fetchApi(apiUrl)
    .then(responseData => {
        data = responseData
    });
    console.log('second', data)
}

first()
second()

console.log('\n============================================================================================================================\n')


async function firstAsync () {
    console.log("This is firstAsync func")
    const apiUrl = 'http://localhost:8080/fetch/data';
    let data = {}

    await fetchApi(apiUrl)
    .then(responseData => {
        data = responseData
    });
    console.log('firstAsync', data)
}

async function secondAsync () {
    console.log("This is secondAsync func")
    const apiUrl = 'http://localhost:8080/fetch/data';
    let data = {}

    await fetchApi(apiUrl)
    .then(responseData => {
        data = responseData
    });
    console.log('secondAsync', data)
}

firstAsync()
secondAsync()

// 혹은 아래와 같이 사용 가능
// async를 추가하면 함수는 Promise를 반환하기 때문
firstAsync().then((data) => {console.log('firstAsync', data)})
secondAsync().then((data) => {console.log('secondtAsync', data)})

// 출력
This is first func
first {}
This is second func
second {}

============================================================================================================================

This is firstAsync func
This is secondAsync func
secondAsync { data3: 'LogLAY', data2: 'DQCAT3.1', data1: 'DQCAT3' }
firstAsync { data3: 'LogLAY', data2: 'DQCAT3.1', data1: 'DQCAT3' }
728x90
Comments