[JavaScript] 비동기 처리 패턴

19319 단어 JavaScriptJavaScript

1. 비동기 처리란?


특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고, 순차적으로 다음 코드를 먼저 실행하는 자바스크립트의 특성

2. Callback


// Asynchronous callback
function printWithDelay(print, timeout) {
    setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);

콜백 함수는 코드를 통해 명시적으로 호출하는 함수가 아니라, 개발자는 단지 함수를 등록하기만 하고, 어떤 이벤트가 발생했거나 특정 시점에 도달했을 때 시스템에서 호출되는 함수

하지만 비동기 작업이 길어질수록 콜백이 깊어지는데 이와 같은 방법은 'callback hell' (콜백 지옥) 이라는 문제점이 발생하며 가독성이 매우 떨어짐

3. Promise


특정 코드의 실행이 완료되면 다음 코드를 실행되도록 처리해주는 함수

Promise의 3가지 state

1) pending(대기 상태): 프로미스가 만들어져서 operation이 실행되는 상태

2) fulfilled(성공 상태): operation이 성공적으로 완료된 상태

3) rejected:(실패 상태): 파일을 찾을 수 없거나 문제가 있는 상태

Producer

promise는 원하는 기능을 수행해서 해당하는 데이터를 만들어내는 producer와(=produce object)와데이터를 소비하는 consumer로 나누어짐

// 1.Producer
// when new Promise is create, the executor runs automatically.
const promise = new Promise((resolve, reject) => {
    // doing some heavy work (network, read files)
    console.log('doing somthing...');
    setTimeout(() => {
        resolve('ellie');
        //reject(new Error('no network'));
    }, 2000);
});

promise는 클래스이기 때문에 new라는 키를 활용해 object를 생성

어떤 작업을 2초 정도 하다가 작업이 완료가 되면 resolve()라는 콜백함수를 호출하고 ellie라는 값을 전달

Consumer

consumers는 then이나 catch 그리고 새롭게 추가된 finally를 활용해 데이터를 받아옴

// 2.Consumer: then, catch, finally
promise
    .then(value => {
        console.log(value);
    })
    .catch(error => {
        console.log(error);
    })
    .finally(() => {
        console.log('finally')
    });

then은 위에서 생성한 promise에서 작업이 정상적으로 실행된 뒤에 resolve()로 받아온 value를 받아와서 실행

catch는 reject() 호출 시 Error 메시지를 좀 더 명확하게 알려줌

finally는 resolve이든 reject이든 어떤 상황에서도 작업을 실행함

Promise Chaining

// 3. Promise chaing
const fetchNumber = new Promise((resolve, reject) => {
    setTimeout(() => resolve(1), 1000);
});

fetchNumber
.then(num => num * 2)
.then(num => num * 3)
.then(num => {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(num - 1), 1000);
    });
})
.then(num => console.log(num));

처음에 생성한 promise의 setTimeout()의 1000ms와 then에서 받은 promise안의 setTimeout()의 1000ms를 합해서 2초 뒤에 5라는 숫자가 출력

Promise chaining은 위 코드와 같이 promise를 엮는 행위임

4. Async / Await


Async와 Await은 promise를 좀 더 편하게 사용할 수 있음

Async

// 1. async
async function fetchUser() {
    // do network request in 10 secs....
    return 'ellie';
}

const user = fetchUser();
user.then(console.log)
console.log(user);

promise를 생략하고 함수 앞에 async를 붙여 편리하게 비동기 코드 작성

Await

Await은 async가 붙은 함수에서만 쓸 수 있음

// 2.await
function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function getApple() {
    await delay(2000);
    throw 'error';
    return '🍎';
}

async function getBanana() {
    await delay(1000);
    return '🍌';
}

async function pickFruits() {
    const applePromise = getApple();
    const bananaPromise = getBanana();
    const apple = await applePromise;
    const banana = await bananaPromise;
    return `${apple} + ${banana}`
}

pickFruits().then(console.log);

await은 메소드의 실행을 일단 중지시킴. promise의 값이 실행되기 전까지 '기다려' 라는 뜻

Promise.all()

promise를 병렬적으로 실행하여 성능향상

// 3, useful Promise APIs
function pickAllFruits() {
    return Promise.all([getApple(), getBanana()]).then(fruits => 
        fruits.join(' + ')
    );}
pickAllFruits().then(console.log)

Promise.race()

배열에 전달된 promise 중에서 가장 먼저 전달된 데이터만 호출

function pickOnlyOne() {
    return Promise.race([getApple(), getBanana()]);
}

pickOnlyOne().then(console.log)

좋은 웹페이지 즐겨찾기