비동기 패턴 해결 - Promise
이전 글에서 콜백형태로 비동기 처리하는 방법을 다뤘습니다.
2022.02.05 - [Study/Express(node.js)] - node.js ) 비동기 패턴 해결 (1) - 콜백함수
하지만 콜백 형태를 이용해 비동기를 처리하면, 처리는 가능하지만 매우 비효율적으로 코드가 작성됩니다.
코드가 화살표 형태로 되거나 함수를 계속 쪼개서 타고 들어가는 형태가 되어 코드의 가독성이 많이 떨어지게 됩니다.
이를 해결하기 위해 사용되는 패턴이 Promise 패턴입니다.
Promise 패턴을 이용하면 비동기 형태의 코드를 마치 순서대로 동작하는 것처럼 구현할 수 있습니다.
Promise 객체
Promise 패턴을 사용하기 위해 Promise 객체를 사용합니다.
then 을 통해 체이닝하여 비동기로 동작하는 함수들을 연결하여 동기 형태로 표현합니다.
- test.txt
async test 1
async test 2
const fs = require('fs');
const p = () => {
return new Promise((resolve, reject) => {
fs.readFile('./test.txt', (err, data) => {
if (err) reject(err);
resolve(data.toString())
})
})
}
p().then((result) => {
console.log(1);
console.log(result);
return p();
}).then((result) => {
console.log(2);
console.log(result);
return p();
}).then((result) => {
console.log(3);
console.log(result);
}).catch(err => {
console.log(err)
})
- Promise 를 이용해 객체를 생성하는 함수를 만듭니다.
- promise 객체를 생성할 땐 콜백함수를 하나를 넘깁니다.
- 첫 번째 인자는 resolve, 두 번째 인자는 reject 를 받습니다.
resolve
Promise 객체에 등록한 비동기 함수가 정상적으로 실행이 완료됐다면 resolve 를 호출합니다. 만약 에러가 발생되어 문제가 생기면 reject 를 호출하게 됩니다.
reject
resolve 를 호출하면 then 을 실행하지만 reject 를 호출하면 가장 가깝게 체이닝된 catch 를 실행하게 됩니다.
하지만 각 promise 객체에서 reject 를 감지하기 위해 catch 를 체이닝 하기에는 코드가 복잡해집니다. 이럴 때 then 의 두 번째 인자를 이용할 수 있습니다.
then 의 두 번째 인자 이용
p().then((result) => {
console.log(1);
console.log(result);
return p();
}, (err) => {
console.log('err 발생');
console.log(err);
return p();
}).then((result) => {
console.log(2);
console.log(result);
return p();
}, (err) => {
console.log('err 발생');
console.log(err);
return p();
}).then((result) => {
console.log(3);
console.log(result);
return p();
}, (err) => {
console.log('err 발생');
console.log(err);
return p();
})
- then 은 이전에 체이닝된 Promise 객체에서 resolve 가 호출되면 첫 번째 인자가 호출되고, reject 가 호출되면 두 번째 인자가 호출됩니다.
catch 로 reject 를 처리하는 것과 then 의 두 번째 인자로 reject 를 처리하는 것의 차이
- catch 는 promise 객체가 실행되다가 reject 가 호출되면 다음 체인 중 catch 로 이동하여 실행하게 됩니다.
그리고 해당 지점부터 코드 실행을 지속합니다. - then의 두 번째 인자로 에러처리를 할 경우에는 바로 이전 체인의 promise 객체가 reject 를 호출할 때만 실행됩니다.
- 각 Promise 의 reject 를 확인한다면 then 의 두 번째 인자를 활용하고, Promise 객체를 단위로 reject 를 검사해야 한다면 catch 를 사용하는 것이 효과적입니다.
Promise.all()
Promise.all() 은 Promise 객체로 된 것이 순서에 상관없이 실행된다면 동시에 실행시켜줄 때 사용합니다.
앞에서 파일을 읽는 promise 객체를 만들었습니다. 사실 파일을 읽는 부분은 순서와는 크게 상관없습니다.
이럴 때는 Promise.all() 을 이용해 편리하게 실행할 수 있습니다.
const fs = require('fs');
const p = (val) => {
return new Promise((resolve, reject) => {
fs.readFile('./test.txt', (err, data) => {
if (err) reject(err);
resolve(`${val} : ${data.toString()}`)
})
})
}
Promise.all([p('1'), p('2'), p('3')]).then((result) => {
console.log(result)
});
- Promise.all 은 then 으로 처리된 결과를 리스트 형태로 받습니다.
- 리스트의 길이는 Promise.all() 로 넘긴 Promise 로 이루어진 배열의 길이와 같습니다.
Promise 패턴을 이용해 비동기 처리를 동기 처리처럼 처리하는 방법을 다뤘습니다.
하지만 async/await 을 이용하면 더 보기 좋은 형태로 비동기를 처리할 수 있습니다.
다음 글에서 async/await 을 이용한 비동기 패턴 해결을 확인할 수 있습니다
'Study > Express(node.js)' 카테고리의 다른 글
node.js ) 비동기 패턴 해결 (3) - async/await (0) | 2022.02.05 |
---|---|
node.js ) 비동기 패턴 해결 (1) - 콜백함수 (0) | 2022.02.05 |
node.js ) 비동기 (asynchronous) 패턴 (0) | 2022.02.05 |
express ) express-generator 프로젝트 생성하기 (0) | 2022.02.05 |
express ) 미들웨어 (0) | 2022.02.04 |
댓글