Skip to main content

Command Palette

Search for a command to run...

Asynchronous Programming In Javascript - Async & Await

Updated
•4 min read•View as Markdown

1] Async Fuctions

1) 정의

Async & Await은 비동기 함수를 동기 함수처럼 코드를 짜게 해주는 문법(통사적 특징, syntactic feature)이라고 할 수 있다.

2) Async

Async를 함수에 쓰게 되면 비동기 함수가 된다.

비동기 함수는 event loop에서 비동기적으로 동작하는 함수이다.

Example

async function f() {
    // code
}

3) Async의 리턴

Async function은 항상 Promise를 리턴한다.

만약 함수가 Promise를 리턴하지 않고 value만 리턴하면, Javascript는 자동적으로 Promise로 래핑한다.

따라서 값일 경우에는 같은 값을 가진 fulfilled Promise를 리턴한다.

이미 Promise를 리턴하고 있으면, 변화(modification) 없이 그대로 리턴한다.

3초 뒤에 fulfilled되는 Promise를 리턴할 경우, 3초 전에 pending이었다가 3초 후에 fulfilled가 되는 모습을 볼 수 있다.

2] Await Keyword

await은 일반 function에 사용할 수 없고, async function에만 사용 가능하다.

await은 Promise가 resolved되거나 rejected가 되는 것에 상관 없이 settled 될 때까지 기다릴 때 사용한다.

중요한 점은 Promise를 기다리므로, Promise는 pending 상태가 아니게 된다는 것이다.

Example

function getOne() {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(1), 3000);
    });
}

async function f() {
    const num = await getOne();
    console.log(num);
}

f();

이렇게 코드를 짤 경우 3초 뒤에 1이 나오게 된다.

따라서 f()는 getOne()에서 Promise가 resolved되거나 rejected 될 때까지 기다린다는 것을 알 수 있다.

Promise가 resolved가 되면 값을 num 변수에다가 할당하게 된다.

그러나 이것은 전체 어플리케이션이 이 함수가 resolved 될 때까지 멈춘다는 것은 아니다.

Javascript engine은 이 함수가 멈춘 동안에 다른 함수나 이벤트를 처리할 수 있다.

Async Await을 사용하여, 기존의 Promise를 사용하는 함수를 쉽게 대체할 수 있다.

Example) 기존 Promise처럼 사용하려면 다음과 같이 사용 가능하다.
function f() {
    getOne()
        .then(num => console.log(num));
}

3] Async Await의 사용

Promise를 사용한 코드와 비교해 보았을 때, 기본적으로 then을 사용한 모든 부분에 await을 써주면 된다.

Example) Promise 사용

function getFetch() {
    fetch('https://www.~~~') // url
        .then(response => response.json())
        .then(value => console.log(value.message));
}

Example) Async Await 사용

async function getFetch() {
    let response = await fetch('https://www.~~~');  // url
    let value = await response.json();
    console.log(value.message));
}

4] Top Level Await

브라우저가 아닌 Node.js에서, ECMAscript module이 아닐 경우 await은 top level에 적용할 수 없다.

Example) 브라우저일 때

Example) Node.js일 때(ECMAscript module이 아닐 때)

package.json에 "type": "module"을 사용하거나, mjs파일로 만들면 실행 가능하다.

5] Handling Errors

1) 전통적인 try catch 사용

Async Await은 try catch를 사용할 수 있다.

2) then 또는 catch 사용

async function은 항상 Promise를 리턴하므로, then이나 catch를 사용할 수 있다.

Further Details

handle function을 통한 최신 비동기 로직 코드

// handle 함수 생성
const handle = async (promise) -> {
    try {
        const data = await promise;
        return [data, undefined];
    } catch (error) {
        return [undefined, error];
    }

}

// 사용
const [response, error] = await handle(비동기 함수);
if (error) {
    alert("Error occurred!");
    return;
}

// 추후 response 사용

6] Sequential and Parallel Execution

1) 순차적(Sequential) 실행

Async Await을 그냥 사용하게 되면, 순차적으로 실행이 된다.

Example

function getOne() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('one');
            resolve(1);
        }, 3000);
    });
}

function getTwo() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('two');
            resolve(2);
        }, 3000);
    });
}

async function f() {
    const one = await getOne();
    const two = await getTwo();
    console.log(one, two);
}

f();

3초후 1이 나오고, 2초 후 2가 나오게 된다.

2) 병렬적(Parallel) Execution

함수가 아닌 response에 await을 사용하면 된다.

Promise.all과 같다.

Example

function getOne() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('one');
            resolve(1);
        }, 3000);
    });
}

function getTwo() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('two');
            resolve(2);
        }, 3000);
    });
}

async function f() {
    const response1 = getOne();
    const response2 = getTwo();
        const one = await response1;
        const two = await response2;
    console.log(one, two);
}

f();

3초후 1과 2가 같이 나오게 된다.

Further Details

f()를 리팩토링하면 다음과 같이 사용할 수도 있다.

Example) response를 한 번에 할당

async function f() {
    const response1 = getOne();
    const response2 = getTwo();
        const [one, two] = [await response1, await response2];
    console.log(one, two);
}

Example) console.log에 직접 입력

async function f() {
    const response1 = getOne();
    const response2 = getTwo();
    console.log(await response1, await response2);
}

More from this blog

RFC 9110 HTTP Semantics - TRACE

1] TRACE trace는 요청 메시지의 원격 application-level의 loop-back을 요청한다. 요청의 최종 수신자(final recipient)는 민감한 데이터를 포함한 필드를 제외하고 수신한 메시지를 200(OK) 응답의 내용으로 클라이언트에 다시 반영해야 합니다.(should) message/http 형식은 이를 수행하기 위한 한 가지 방법이다. 최종 수신자는 Origin Server이거나 요청에서 Max-Forwards ...

Nov 28, 20241 min read

RFC 9110 HTTP Semantics - POST

1] POST POST 메서드는 target resource가 리소스 자체의 특정한 의미에 따라 요청에 포함된 representation을 처리하도록 요청한다. 예를 들어, 다음의 기능을 수행한다. HTML form에 입력된 필드같은 데이터 블록을 데이터 처리 프로세스에 제공 게시판, 뉴스 그룹, 메일링 리스트, 블로그, 또는 비슷한 기사 그룹에 메시지 게시(posting) origin server에서 식별되지 않은 새로운 리소스 생성 ...

Nov 2, 20242 min read

RFC 9110 HTTP Semantics Method Definitions GET

1] GET GET Method는 대상 리소스에 대한 현재 선택된 representation의 전송을 요청한다. 성공적인 응답은 대상 URI가 식별한 동일성의 품질을 반영한다.(계속 요청하면 항상 동일한 응답을 줌) 따라서 HTTP를 통해 식별 가능한 정보를 검색하는 것은 일반적으로 GET 요청을 통해 수행되며 200(OK) 응답을 준다. 리소스 식별자를 원격 파일 시스템 경로명으로, representation을 해당 파일 콘텐츠의 복사본으로 ...

Oct 9, 20243 min read

Spring Data JPA Dynamic Projections

1] 기존 Projections 특정한 Entity의 컬럼을 전부 가져오고 싶지 않을 때, 기존의 경우는 메서드마다 record를 생성하였다. 이때, 출처에서 적힌 것처럼, 여러 메서드가 하나의 record를 쓰는 경우가 생기게 된다. 예를 들어, 컬럼이 id, name, genre, 등등이 있을 때 기존에 id와 name만을 가져오는 record가 있을 경우 id, name, genre를 가져오는 메서드를 만들 경우 기존의 record에 ge...

Sep 25, 20242 min read

Jong-Dae's Coding Docs

17 posts