Dev/Node.js

[Node.js] 03 - Promise

min8282 2024. 4. 22. 03:39

프로미스에 대해 시작하기 앞서 프로미스나인 영상을 시청하겠다.

https://youtu.be/8uOBj0pINT8?si=PUE1LcmvKD0vgObJ

 

잘 시청했길 바란다.


프로미스(Promise)

프로미스는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체다.

new Promise(): 작업의 최종 완료 또는 실패에 관한 메시지를 반환

- resolve(성공 리턴 값): 작업 성공 시 호출될 callback 함수

- reject(실패 리턴 값): 실패 시 호출될 callback 함수

 

.then()

- Promise 정상 수행 후 실행

- resolve를 통해서 전달한 값이 매개변수로 전달됨

 

.catch()

- 오류 발생 시 실행

- reject를 통해 전달한 값이 매개변수로 전달됨

 

.finally()

- 성공, 실패 모든 경우에 실행

// 1. Promise generate
const promise = new Promise ( (resolve, reject) => {
    console.log('reading file...');
    setTimeout(()=> {
        let read = true;
        if (read) {
            resolve('file read success!');
        } else {
            reject(new Error('File read fail.'));
        }
    }, 2000);
});
// 2. then, catch, finally
promise
    .then(value => {
        console.log(value);
    })
    .catch(error => {
        console.log(error);
    })
    .finally(()=> {
        console.log('finally');
    });

 

✅ Promise Chaining

- then 안에서 return한 값이 다음 then으로 전달된다.

- return 값이 프로미스면 resolve 후 전달

- 에러 발생은 catch에서 한 번에 처리

// 3. Promise chainging
const fetchData = new Promise( (resolve, reject)=> {
    setTimeout(()=> resolve('Carrot', 1000));
});

fetchData
    .then(data => data + ' Cheese')
    .then(data => data + ' Cake')
    .then(data => {
        return new Promise( (resolve, reject)=> {
            setTimeout(()=>resolve(data+'!'),1000);
        });
    })
    .then(data => console.log(data))
    .catch(error => {
        console.log(error);
    });

// 출력 결과 >> Carrot Cheese Cake !

 

Callback hell에 대한 해결책이다.

- 콜백 헬이란 여러 개의 중첩된 콜백이 비동기 작업을 처리하는 데 사용되어 코드가 깊게 중첩되고 읽기 어려운 상황을 뜻한다.

- 먼저 Callback hell이 발생하는 상황을 보겠다.

- 아래 코드는 두 개 이상의 비동기 작업과 중첩된 콜백 함수를 순차적으로 실행하는 코드다.

function loginUser(id, password, callback) {
    setTimeout(() => {
        console.log('사용자 정보 얻음');
        const user = { userId: id };
        callback(user);
    }, 3000);
}

function getUserMovies(id, callback) {
    setTimeout(() => {
        callback(['Titanic', 'Home Alone', 'AVATAR']);
    }, 2000);
}

function movieDetails(movie, callback) {
    setTimeout(() => {
        callback('영화 제목은 ...');
    }, 2000);
}

const user = loginUser('msjwa', 215, user => {
    console.log(`${user.userId}님 환영합니다.`);
    getUserMovies(user.userId, (movies) => {
        console.log(movies);
        movieDetails(movies[0], title => {
            console.log(title);
        });
    });
});

실행 결과

이런 비동기 작업과 중첩 콜백이 여러 개가 추가되면 추가될수록 코드를 이해하고 유지 관리하기가 점점 더 어려워질 것이다. 이를 방지하기 위한 해결책이 바로 프로미스다. 위 코드를 프로미스로 수정해 보겠다.

function loginUser(id, password) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('사용자 정보 얻음');
            const user = { userId: id };
            resolve(user);
        }, 3000);
    });
}

function getUserMovies(id) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(['Titanic', 'Home Alone', 'AVATAR']);
        }, 2000);
    });
}

function movieDetails(movie) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('영화 제목은 ...');
        }, 2000);
    });
}

loginUser('msjwa', 215)
    .then(user => {
        console.log(`${user.userId}님 환영합니다.`);
        return getUserMovies(user.userId);
    })
    .then(movies => {
        console.log(movies);
        return movieDetails(movies[0]);
    })
    .then(title => {
        console.log(title);
    })
    .catch(error => {
        console.error(error);
    });

이와 같이 수정하게 되면 코드의 흐름을 잘 따라갈 수 있어 유지보수하는 데 큰 도움이 될 것이다. 다음에는 이런 프로미스 기반 코드를 좀 더 쓰기 쉽고 읽기 쉽게 하고, 비동기 코드를 동기식으로 작성할 수 있는 async/await에 대해 공부해 보겠다.