# Promise
ํ๋ผ๋ฏธ์ค๋ ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌ๋ฅผ ๋ํ๋ด๋ ๊ฐ์ฒด์ ๋๋ค. ๋น๋๊ธฐ ์์ ์ฒ๋ฆฌ์ ์์ด์ ๊ธฐ์กด์ ์ฝ๋ฐฑ(Callback) ํจ์ ๋ฐฉ์์ ๋ฌธ์ ์ ์ (opens new window) ๊ฐ์ ํ ๋ฐฉ์์ ๋๋ค.
# ํ๋ผ๋ฏธ์ค๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์
๋น๋๊ธฐ์ ์์ ์ฒ๋ฆฌ์ ์์ด์ ๊ธฐ์กด์ ์ฝ๋ฐฑ ๋ฐฉ์์์ ๋ฒ์ด๋ ํ๋ผ๋ฏธ์ค๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ฝ๋ฐฑ ์ง์ฅ์(Pyramid of Doom) ํด๊ฒฐ
- ์๋ฌ์ ์ฒ๋ฆฌ์ ์ฉ์ด์ฑ
# 1. ์ฝ๋ฐฑ ์ง์ฅ(Pyramid of Doom)
๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํด์ผ ํ ์์ ์ด ๋ ์ด์์ด๋ผ๊ณ ๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฅผ ์ฝ๋ฐฑ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
loadScript('1.js', function(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('2.js', function(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('3.js', function(error, script) {
if (error) {
handleError(error);
} else {
// ...continue after all scripts are loaded (*)
}
});
}
});
}
});
์ ์ฒด์ ์ธ ์ฝ๋์ ํ๋ฆ์ ์ ๋ฆฌํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1.js
ํ์ผ์ ๋ถ๋ฌ์ต๋๋ค. ํ์ผ์ ๋ถ๋ฌ์ค๋ ๊ณผ์ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ์ฒ๋ฆฌํฉ๋๋ค.1.js
ํ์ผ์ ์ ์์ ์ผ๋ก ๋ถ๋ฌ์๋ค๋ฉด,2.js
ํ์ผ์ ๋ถ๋ฌ์ต๋๋ค. ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ์ฒ๋ฆฌํฉ๋๋ค.2.js
ํ์ผ์ ์ ์์ ์ผ๋ก ๋ถ๋ฌ์๋ค๋ฉด,3.js
ํ์ผ์ ๋ถ๋ฌ์ต๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ์ฒ๋ฆฌํฉ๋๋ค.
์ฒ๋ฆฌํด์ผ ํ ์์ ์ด ๋ง์์ง์๋ก ์ฝ๋๊ฐ ๋พฐ์กฑํ์ฒ๋ผ ์ค๋ฅธ์ชฝ์ผ๋ก ์น์ฐ์น๋ ํํ๋ฅผ ๋ณด์ด๊ฒ ๋ฉ๋๋ค. ์ด๋ฌํ ํจ์ ์ค์ฒฉ์ ๋ชจ์์ด ํผ๋ผ๋ฏธ๋์ ๋น์ทํ๋ค๊ณ ํ์ฌ Pyramid of Doom์ผ๋ก ๋ถ๋ฆฌ๊ฒ ๋์์ต๋๋ค.
์์ ์์์์ ๋ณผ ์ ์๋ฏ ์ฝ๋ฐฑ ์ง์ฅ์ ์ฝ๋์ ๊ฐ๋ ์ฑ์ ์ ํดํ๊ฒ ๋์ง๋ง ํ๋ผ๋ฏธ์ค๋ฅผ ํ์ฉํ๋ฉด ์ด๋ฌํ ๋ฌธ์ ์ ์ ํด๊ฒฐํ ์ ์๊ฒ ๋ฉ๋๋ค.
# 2. ์๋ฌ์ ์ฒ๋ฆฌ
์ฌ์ค ์ฝ๋ฐฑ ์ง์ฅ์ ํ๋ผ๋ฏธ์ค๋ฅผ ํ์ฉํ์ง ์๊ณ ๋ ํด๊ฒฐํ ์ ์์ต๋๋ค. ์ต๋ช ํจ์์ ์ฌ์ฉ์ ํฌ๊ธฐํ๊ณ ์ฝ๋ฐฑ ํจ์๋ค์ ๋ถ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ํตํด ํด๊ฒฐ ๊ฐ๋ฅํฉ๋๋ค.
loadScript('1.js', step1);
function step1(error, script) {
if (error) {
handleError(error);
} else {
// ..
loadScript('2.js', step2);
}
}
function step2(error, script) {
if (error) {
handleError(error);
} else {
// ..
loadScript('3.js', step3);
}
}
// step3, step4 ....
์์ ์์์ฒ๋ผ ์ฝ๋ฐฑ ํจ์์ ๋ถ๋ฆฌ๋ฅผ ํตํด ์ฝ๋์ ๊ฐ๋
์ฑ์ ๋์ผ ์ ์์์๋ ํ๋ผ๋ฏธ์ค๊ฐ ๋ ๋ฐ๋์งํ ์ด์ ๋ ์๋ฌ ์ฒ๋ฆฌ๊ฐ ์ฝ๋ค๋ ์ธก๋ฉด์ ์์ต๋๋ค. ํ๋ผ๋ฏธ์ค๋ฅผ ํตํ ์๋ฌ ์ฒ๋ฆฌ๋ ๋ค์์ ์ค๋ช
ํ .then
, .catch
๋ฉ์๋๋ฅผ ํตํด ๊ฐ๋จํ ์ ๋ฆฌ ๊ฐ๋ฅํฉ๋๋ค.
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error('Error!'));
document.head.append(script);
});
}
loadScript('callback.js')
.then(console.log)
.catch(console.log);
# ๊ธฐ๋ณธ ๋ฌธ๋ฒ
์์ฑ์ ํจ์๋ฅผ ํ์ฉํ ํ๋ผ๋ฏธ์ค ๊ฐ์ฒด ์์ฑ ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
const promise = new Promise((resolve, reject) => {
// executor
}
Promise()
์์ฑ์์ ์ ๋ฌ๋๋ ํจ์๋ ์คํ ํจ์(executor)๋ก, ๊ฐ์ฒด ์์ฑ ํ ์๋์ ์ผ๋ก ์คํ๋ฉ๋๋ค.
# ํ๋ผ๋ฏธ์ค ๊ฐ์ฒด ํ๋กํผํฐ
ํ๋ผ๋ฏธ์ค ๊ฐ์ฒด๋ ๋ ๊ฐ์ง ํ๋กํผํฐ(properties)๋ฅผ ๊ฐ์ง๋๋ค.
์ํ(state):
pending
์ผ๋ก ์ด๊ธฐํ๋๋ฉฐresolve
๊ฐ ํธ์ถ๋ ์fulfilled
๋ก,reject
๊ฐ ํธ์ถ๋ ์rejected
๋ก ๋ฐ๋๋๋ค.rejected
,resolved
๋ ์ํ๋ฅผ ํต์นญํ์ฌsettled
์ํ ๋ผ๊ณ ํฉ๋๋ค.๊ฒฐ๊ณผ(result):
undefined
๋ก ์ด๊ธฐํ๋๋ฉฐresolve(value)
๋ฉ์๋๊ฐ ํธ์ถ๋ ์value
๋ก,reject(error)
๋ฉ์๋๊ฐ ํธ์ถ๋ ์error
๋ก ๋ฐ๋๋๋ค.
# ๊ธฐ๋ณธ ์์
๋ค์์ ์์ ๋ ๋ณ๋์ ํํฐ๋ง ์์ด ํ๋ผ๋ฏธ์ค ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ค console.log(promise)
๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ์ดํด๋ด
๋๋ค.
const promise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('success');
}, 1000);
});
console.log(promise);
ํ๋ผ๋ฏธ์ค ๊ฐ์ฒด์ ์คํ ํจ์๋ฅผ 1์ด๊ฐ ์ง๋ ๋ค์ ์คํํ๊ฒ๋ ์ค์ ํด๋์์ผ๋ฏ๋ก, ์์ ์์ ๋ฅผ ํ ๋ฒ์ ์คํํ๊ฒ ๋๋ฉด ์ฝ์ ์์ ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋ํ๋ฉ๋๋ค.
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "pending"
[[PromiseResult]]: undefined
์ดํ 1์ด๊ฐ ์ง๋ ์์ ์์ ๋ธ๋ผ์ฐ์ ์ฝ์ ์์ console.log(promise)
๋ก ๊ฐ์ฒด๋ฅผ ์ฌํ์ธํ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Promise {<fulfilled>: "success"}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "success"
# ์ฃผ์์ฌํญ
- ํ๋ผ๋ฏธ์ค๊ฐ์ฒด์ ์คํ ํจ์๋ ๋จ ํ๋์
resolve
๋๋reject
๋ง ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
const promise = new Promise((resolve, reject) => {
resolve('done!');
reject(new Error('error')); // ignored
setTimeout(() => {
resolve('..');
}, 1000);
});
ํ๋ผ๋ฏธ์ค์
reject
๋resolve
์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ธ์์ ์ด๋ ํ ํ์ ์ด ์๋ ์๊ด์์ง๋ง,Error
๊ฐ์ฒด์ ํจ๊ป ์ฒ๋ฆฌํ๋ ๊ฒ์ด ๊ถ์ฅ๋ฉ๋๋ค. ๊ทธ ์ด์ ๋ ๋ค์์ ๋ฌธ์ (opens new window)๋ฅผ ์ฐธ์กฐํ์ธ์.resolve
์reject
๋ ๊ผญ ๋น๋๊ธฐ์ ์ผ๋ก ํธ์ถ๋์ด์ผ ํ๋ ๊ฒ์ ์๋๋๋ค.
const promise = new Promise((resolve, reject) => {
resolve(123);
});
- ํ๋ผ๋ฏธ์ค ๊ฐ์ฒด์
state
์result
๋ ์ธ๋ถ์์ ์ ๊ทผํ ์ ์์ต๋๋ค..then
,.catch
,.finally
๋ฉ์๋๋ฅผ ํตํด ๋ค๋ค์ง ์ ์์ต๋๋ค.
# then, catch, finally
# 1. then
.then
๋ฉ์๋๋ ์ฒซ ๋ฒ์งธ ์ธ์๋ก resolved
์ํ๋ฅผ ์ฒ๋ฆฌํ๋ ํจ์๋ฅผ ๋ฐ๊ณ , ๋ ๋ฒ์งธ ์ธ์๋ก๋ rejected
์ํ๋ฅผ ์ฒ๋ฆฌํ๋ ํจ์๋ฅผ ๋ฐ์ต๋๋ค.
promise.then(
function(result) {
// resolved!
},
function(error) {
// rejected!
}
);
# 2. catch
ํ๋ผ๋ฏธ์ค ๊ฐ์ฒด์ ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ ๋ (rejected๋ ๊ฒฝ์ฐ) ์ฌ์ฉ๋ฉ๋๋ค. .catch
๋ฉ์๋๋ .then
๋ฉ์๋์ ์ฒซ ๋ฒ์งธ ์ธ์์ null
์ ์ ๋ฌํ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์๋ํ๊ฒ ๋ฉ๋๋ค.
const asyncThing = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Error!')), 1000);
});
asyncThing.catch(alert); // same as promise.then(null, alert)
ํ๋ผ๋ฏธ์ค์ ์๋ฌ ์ฒ๋ฆฌ๋ ๊ฐ๊ธ์ .catch
๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ๊ทธ ์ด์ ๋ Javascript.info - Error handling with promises (opens new window)๋ฌธ์์ ์๊ฐ๋์ด ์์ต๋๋ค.
# 3. finally
.finally
๋ฉ์๋๋ ํ๋ผ๋ฏธ์ค๊ฐ settled
์ํ์ผ ๋ ํธ์ถ๋ฉ๋๋ค. Promise ๊ฐ์ฒด ์ ์ ํ, ์์
์ฒ๋ฆฌ์ ์ฑ๊ณต ๋ฐ ์คํจ ์ฌ๋ถ์ ์๊ด์์ด, .finally
๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ธฐ๋ง ํ๋ฉด ๋ฌด์กฐ๊ฑด ํธ์ถ๋๋ ๋ฉ์๋์
๋๋ค.
.finally
๋ ์ธ์๋ฅผ ๋ฐ์ง ์์ต๋๋ค.
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('result!'), 1000);
});
promise
.then(console.log);
.finally(() => {
alert('promise ready!');
})
# ํ๋ผ๋ฏธ์ค๋ฅผ ํ์ฉํ ๋น๋๊ธฐ์ฒ๋ฆฌ ์์
๋ค์ ๋ ์์ ๋ ๋ชจ๋ ์ ์ด์ฟผ๋ฆฌ(jquery)์ $.get
๋ฉ์๋๋ฅผ ํ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํฉ๋๋ค.
์ฒซ ๋ฒ์งธ ์์ ์ฝ๋๋ ๋น๋๊ธฐ์ ์ผ๋ก ๋์ํ๋ $.get
๋ฉ์๋๋ก ์ธํด ์์ฒญ์ ๋ํ ์๋ต ๊ฐ์ ๋ณ์ todo
์ ์ ์ฅํ์ฌ๋ ๊ฒฐ๊ณผ๋ฌผ์ undefined
๋ก ๋ํ๋๊ฒ ๋ฉ๋๋ค. ์ด๋ ์์ฒญ์ ๋ํ ์๋ต ๊ฐ์ ์ ์์ ์ผ๋ก ํ์ธํ์ง ๋ชปํ๋ค๋ ์๋ฏธ์
๋๋ค.
function getTodo() {
let todo;
$.get('https://jsonplaceholder.typicode.com/todos/1', function(response) {
todo = response;
});
return todo;
}
console.log(getTodo()); // undefined
์ด๋ฌํ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๊ธฐ ์ํด ํ๋ผ๋ฏธ์ค๋ฅผ ํ์ฉํฉ๋๋ค.
function getTodo() {
return new Promise((resolve, reject) => {
$.get('https://jsonplaceholder.typicode.com/todos/1', (response) => {
resolve(response);
});
});
}
getTodo().then(console.log);
์์ ์์ ์์๋ getTodo
ํจ์์์ ํน์ ๋ณ์๊ฐ์ ๋ฐํํ๋ ๊ฒ์ด ์๋๋ผ ํ๋ผ๋ฏธ์ค๋ฅผ ์์ฑํ์ฌ ๋ฐํํ๊ฒ ๋ฉ๋๋ค. ์ด๋ ํ๋ผ๋ฏธ์ค์ ์ฝ๋ฐฑ์ธ resolve
ํจ์์ ์์ฒญ์ ๋ํ ์๋ต ๊ฐ์ ๋ด๊ฒ ๋ฉ๋๋ค.
$.get()
๋ฉ์๋๋ฅผ ํตํด ์์ฒญ์ ๋ณด๋ธ URL๋ก๋ถํฐ ์ ์์ ์ผ๋ก ์๋ต์ด ์ค๊ณ ๋๋ฉด resolve
์ฝ๋ฐฑ์ ํด๋น ์๋ต ๊ฐ์ด ๋ด๊ฒจ .then
๋ฉ์๋๋ก ์ ๋ฌ๋ฉ๋๋ค.
์ดํ ์ฝ๋ฐฑ์ ์ ๋ฌ๋ ์๋ต ๊ฐ์ ์ถ๋ ฅํด๋ณด๋ฉด ์ ์์ ์ผ๋ก ๋ฐ์ดํฐ ์์ ์ด ์ด๋ฃจ์ด์ก์์ ํ์ธํ ์ ์์ต๋๋ค.
# ํ๋ผ๋ฏธ์ค ์ ์ ๋ฉ์๋
โ Destructuring Async & Await โ