Javascript๋ฅผ ์ฌ์ฉํ๋ค๋ณด๋ฉด ๋น๋๊ธฐ call ์์๋ค์ด ๋ง์์ ๋ก์ง์ ๊ฐ๋ ์ฑ๊ณผ ์ค๋ฅ ๋๋ฒ๊น ๋ฌธ์ ๋ฑ์ด ๋ณต์กํ๊ฒ ์ฝํ๊ฒ ๋(์ด๋ฅผ ํฌ์ด๋ผ๊ณ ๋ ํํํ๋๋ฐ), ์ด๋ฅผ ํํผํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ค์ ํ๋๊ฐ Promise๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ๋๋ถ๋ถ ๊ฒฝ์ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ ๊ณตํ๊ณ ์์ด, ๊ทธ ๋ด์ฉ์ ์ ๋ชจ๋ฅด๊ณ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ ์ค์ฉ๋๋ ์ฌ๋ก๋ฅผ ๊ฒฝํํ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋์ ๋ด๋ถ๋ฅผ ์ข ๋ ์ดํดํ๋๋ฐ ๋์์ด ๋๋ ์ข์ ์ํฐํด์ด ์์ด์ ๋ฒ์ญ์ ํด๋ณด์์ต๋๋ค.
์๊ฐ ์ํฐํด์ JavaScript Promises ... In Wicked Detail ์ ๋๋ค. ์์ธํ ๋ด์ฉ์ ์๋๋ฅผ ๋ฐ๋ผ๊ฐ ๋ณด์๋ฉด ๋ ๊ฑฐ ๊ฐ๋ค์.
์ Promise๊ฐ ํ์ํ๊ฐ?
์ Promise์ ๋ํด์ ๋ํ ์ผํ๊ฒ ์ดํดํ๋๋ฐ ์ ๊ฒฝ์ ์จ์ผํ ๊น? ์ค์ Promise๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง๋ฅผ ์๋ค๋ ๊ฒ์ ๊ทธ๊ฒ์ ํ์ฉํ๋ ๋ฅ๋ ฅ์ด ํฅ์๋๊ณ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋์๋ ๋ ์ฑ๊ณต์ ์ผ๋ก ๋๋ฒ๊น ์ ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ด ์ํฐํด์ ์ฐ๊ฒ๋ ๊ณ๊ธฐ๋ ๋๋ฃ์ ๋ด๊ฐ Promise์ ๊น๋ค๋ก์ด ๊ฒฝ์ฐ๋ฅผ ์ ํด์ ๊ณ ์ํ ์ ์ด ์์๋ค. ์ง๊ธ Promise์ ๋ํด ์์๋ ๊ฒ์ ๊ทธ ๋๋ ์์๋๋ผ๋ฉด ๊ณ ์์ ๋ ํ์ ์ ์์์ ๊ฒ์ด๋ค.
์ฌํํ ์ฌ์ฉ ์ฌ๋ก
๋จผ์ ๊ฐ์ฅ ๊ฐ๋จํ Promise์ ๋ํ ๊ตฌํ์ ์ดํด๋ณด์. ๋ค์ ํจ์๊ฐ ์๋ค๊ณ ๊ฐ์ ํ๋ค.
doSomething(function(value) {
console.log('Got a value:' + value);
});
์ด ํจ์๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ ค ํ๋ค.
doSomething().then(function(value) {
console.log('Got a value:' + value);
});
์์ฒ๋ผ ํ๊ธฐ ์ํด doSomething()์์ ๋ค์๊ณผ ๊ฐ์ ๋ถ๋ถ์ ๋ณ๊ฒฝํด์ผ ํ๋ค.
function doSomething(callback) {
var value = 42;
callback(value);
}
๋ค์๊ณผ ๊ฐ์ด Promise ๊ธฐ๋ฐ์ผ๋ก ๋ณ๊ฒฝํ๋ค.
function doSomething() {
return {
then: function(callback) {
var value = 42;
callback(value);
}
};
}
์ด ๊ตฌํ์ Callback ํจํด์ ๋จ์ํ ๋์ฒด์ด๋ฉฐ, ์ด๊ฒ๋ง์ผ๋ก๋ ํฐ ์๋ฏธ๊ฐ ๋์ง ์๋๋ค. ๊ทธ๋ฌ๋ ์์ฃผ ๊ฐ๋จํ ๊ตฌํ์ด์์ง๋ง, Promise์ ํต์ฌ์ ์ธ ์์ด๋์ด๋ฅผ ์ด๋ฏธ ์ดํดํ๋ค๊ณ ๋ณผ ์ ์๋ค.
Promise๋ ๊ฐ์ฒด์์ ๊ถ๊ทน์ ์ผ๋ก ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ๋ฅผ ์์งํ๋ค.
์ด์ ์์ Promise๊ฐ ๋งค์ฐ ํฅ๋ฏธ๋กญ๋ค๊ณ ์๊ฐํ๋ ํฐ ์ด์ ์ด๋ค. ์ผ๋จ Promise ๋ด์ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ ์์ง๋๋ฉด, ๊ทธ ๋ค์์ ๋งค์ฐ ๊ฐ๋ ฅํ๊ฒ ์ผ์ ์งํํ ์ ์๋ค. ์ด ์ ์ ๋ํด์๋ ์ข ๋ ๋์ค์ ์ค๋ช ํ๋ค.
Promise ํ์ ์ ์
์์ ๊ฐ๋จํ ๊ฐ์ฒด ๋ฆฌํฐ๋ด ๊ตฌํ์ ์ ๋์๊ฐ์ง ์์ ๊ฒ์ด๋ค. ์ฐ๋ฆฌ๋ ์์ผ๋ก ์ ์ค๋ช ํ๊ธฐ ์ํด, Promise ํด๋์ค๋ฅผ ์ ์ํ๋ค.
function Promise(fn) {
var callback = null;
this.then = function(cb) {
callback = cb;
};
function resolve(value) {
callback(value);
}
fn(resolve);
}
์ด๋ฅผ ์ฌ์ฉํ์ฌ doSomething()์ ์ฌ๊ตฌํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋๋ค.
function doSomething() {
return new Promise(function(resolve) {
var value = 42;
resolve(value);
});
}
๊ทธ๋ฐ๋ฐ, ์ฌ๊ธฐ์๋ ๋ฌธ์ ๊ฐ ์๋ค. ์คํํด์ ์ถ์ ํ๋ฉด resolve()๊ฐ then()๋ณด๋ค ๋จผ์ ํธ์ถ๋๊ณ ๊ทธ ๊ฒฐ๊ณผ callback์ null์ด ๋๋ค. ์ด ๋ฌธ์ ์ ๋์ํ๊ธฐ ์ํด setTimeout์ ์ฌ์ฉ(ํดํน ์ํ์ด ์์ง๋ง)ํ๋ค.
function Promise(fn) {
var callback = null;
this.then = function(cb) {
callback = cb;
};
function resolve(value) {
// force callback to be called in the next
// iteration of the event loop, giving
// callback a chance to be set by then()
setTimeout(function() {
callback(value);
}, 1);
}
fn(resolve);
}
์ด ์ฝ๋๋ ๋ฌธ์ ๊ฐ ๋ ์์ง๊ฐ ๋ง์ ์ข์ง ์์ ์ฝ๋์ด๋ค.
์ด Promise์ ์ทจ์ฝ์ฑ์ด ๋ง์ ์ฝ๋๋ฅผ ์ ๋๋ก ๋์์ํค๊ธฐ ์ํด์๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ํด์ผํ๋ค. ์ด ๊ตฌํ์์ ์ค๋ฅ๋ฅผ ์ ๋ฐ์ํค๋ ๊ฒ์ ๊ฐ๋จํด์ then()์ ๋น๋๊ธฐ์ ์ผ๋ก ํธ์ถํ๋ผ. ๊ทธ๋ฐ ํ ๋ค์ callback์ null์ด ๋๋ค. ์ ์ด๋ ๊ฒ ์ทจ์ฝํ ์ฝ๋๋ฅผ ์ค์ ํ์๊น? ์์ ๊ตฌํ์ ์์ฃผ ์ดํดํ๊ธฐ ์ฝ๋ค๋ ์์ ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค. ์์ ๊ฐ์ ๊ฐ๋จํ ๊ตฌํ์ ํตํด Promise์์ ์ค์ํ then()๊ณผ resolve()๋ฅผ ๋ช ํํ๊ฒ ์ ์ ์๋ค. then()๊ณผ resolve()๋ Promise์์ ์ค์ํ ๊ฐ๋ ์ด๋ค.
Promise๊ฐ ์ํ๋ฅผ ๊ฐ์ง๋ค.
์ฐ๋ฆฌ์ ์ด์คํ ์ฝ๋๋ ์์์น ๋ชปํ ๊ฒ๋ค์ ๋ฐ์์ํฌ ์ ์๋ค. ๊ทธ๋์ Promise๋ ์ํ๋ฅผ ๊ฐ๋๋ค๋ ๊ฒ์ด๋ค. ์ฐ๋ฆฌ๋ ํ๋ก์ธ์ค๋ฅผ ์งํํ๊ธฐ ์ ์ Promise๊ฐ ์ด๋ค ์ํ์ธ์ง๋ฅผ ์ ํ์๊ฐ ์๊ณ , ๊ทธ๋ฆฌ๊ณ ๊ทธ ์ํ๊ฐ ์ด๋ป๊ฒ ์ด๋ํ๊ณ ์๋์ง๋ฅผ ์ ํํ ์์์ผ ํ๋ค. ์ด์ ์ฝ๋์ ์ทจ์ฝ์ฑ ๋ถ๋ถ์ ์์ ์.
- Promise๋ ๊ฐ์ด ํ์ ๋ ๋๊น์ง pending ์ํ์๋ก ์ ์ง๋์๋ค๊ฐ ๊ฐ์ด ๊ฒฐ์ ๋๋ฉด resolved์ํ๊ฐ ๋๋ค.
- ์ผ๋จ ๊ฐ์ด resolved๋๋ฉด ํญ์ ๊ทธ ๊ฐ์ ์ ์งํ๊ณ ๋ค์ ํ์ธ์ ํ์ง ์๋๋ค.
(Promise์๋ rejected๋ผ๋ ์ํ๋ ์์ง๋ง, ๋์ค์ ์ค๋ฅ ์ฒ๋ฆฌ ๋ ๋ค์ ์ค๋ช ํ๋ค.)
ํดํน์ ๊ฐ๋ฅ์ฑ์ด ์๋ setTimeout์ ์์ ๊ณ ๊ตฌํ์ฒด ๋ด๋ถ์ ์ํ ๋ณํ๋ฅผ ์ถ์ ํ ์ ์๋๋ก ํด๋ณด์.
function Promise(fn) {
var state = 'pending';
var value;
var deferred;
function resolve(newValue) {
value = newValue;
state = 'resolved';
if(deferred) {
handle(deferred);
}
}
function handle(onResolved) {
if(state === 'pending') {
deferred = onResolved;
return;
}
onResolved(value);
}
this.then = function(onResolved) {
handle(onResolved);
};
fn(resolve);
}
์กฐ๊ธ ๋ณต์กํ์ง๋ง ํธ์ถ์(ํธ์ถํ๋ ์ธก)๋ ์ํ๋ ์๊ฐ์ then()์ ํธ์ถํ ์ ์๊ฒ ๋์๋ค. ๊ทธ๋ฆฌ๊ณ ํผํธ์ถ์(ํธ์ถ๋๋ ์ชฝ)๋ ์ธ์ ๋ ์ง resolve()๋ฅผ ๋ถ๋ฅผ ์ ์๊ฒ ๋์๋ค. ๋๊ธฐ๋ ๋น๋๊ธฐ ์ํฉ์์๋ ์๋ฒฝํ๊ฒ ๋์ํ๊ณ ์๋ค.
์ด๋ ๊ฒ ๋ ์ด์ ๋ state ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ด๋ค. then()๊ณผ resolve() ๋ ๋ค ์๋ก์ด ํจ์์ธ handle()์ ์ฒ๋ฆฌ๋ฅผ ์์ํ๋ค. handle()์ ์ํฉ์ ๋ฐ๋ผ ๋๊ฐ์ง ์์ ์ ๊ตฌ๋ถํ๋ค.
- ํผํธ์ถ์ resolve()๋ฅผ ์คํํ๊ธฐ ์ ์ ํธ์ถ์๊ฐ then()์ ์คํํ๋ฉด ๊ฐ์ ๋๋ ค์ค ์ค๋น๊ฐ ๋์ง ์์ ์ํ์ด๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ state๋ pending ์ํ๊ฐ ๋ ๊ฒ์ด๊ณ ํธ์ถ์๊ฐ ์ง์ ํ callack์ด ๋์ค์ ์ฌ์ฉ๋ ๋๊น์ง ์ ์ง๋๋ค. ๊ทธ๋ฐ ํ resolve()๊ฐ ํธ์ถ๋๋ฉด callback์ด ์คํ๋๊ณ ํธ์ถ์์๊ฒ ๊ฐ์ ์ ๋ฌํ๋ค.
- ํธ์ถ์๊ฐ then()์ ํธ์ถํ๊ธฐ ์ ์ ํผํธ์ถ์๊ฐ resolve()๋ฅผ ํธ์ถํ๋ฉด ๊ฐ์ ํ์ ๋ ์ํ๊ฐ ๋๋ค. ์ด ๊ฒฝ์ฐ then()์ด ํธ์ถ๋๋ฉด ๊ฐ์ ๋ฐํํ ์ค๋น๋ฅผ ํ๋ค.
์ฃผ๋ชฉํ ๊ฒ์ setTimeout์ ๊ตฌํ์ฒด๋ ์์ด์ก์ง๋ง, ๊ทธ๊ฒ์ ์ผ์์ ์ด๊ณ ๋์ค์ ๋ค์ ๋ํ๋๋ค. ์์ธํ ๋ด์ฉ์ ๊ทธ ๋ ์ค๋ช ํ๋ค.
Promise๋ฅผ ์ฌ์ฉํ๋ฉด then()๊ณผ resolve()์ ํธ์ถ ์์๋ฅผ ๊ณ ๋ คํ์ง ์์๋ ๋๋ค. then()๊ณผ resolve()๋ ์ฐ๋ฆฌ์ ์ด์ฉ ๋ชฉ์ ์ ๋ฐ๋ผ ์ธ์ ๋ผ๋ ํธ์ถํ ์ ์๋ค. ์ด๊ฒ์ Promise ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ๋ฅผ ๊ฐ์ฒด์ ์ ์ฅํ๋ ๋ฐ ์์ฃผ ํฐ ์ฅ์ ์ค์ ํ๋๋ค.
์ฐ๋ฆฌ๊ฐ ๊ตฌํํด์ผ ํ ์คํ์์๋ ์์ฃผ ๋ง์ ์ผ์ด ์์ง๋ง, ์ฐ๋ฆฌ์ Promise ์ด๋ฏธ ํ์ํํ๋ค. ์ด ๊ตฌํ์ฒด๋ฅผ ์ฌ์ฉํ๋ฉด then()๋ฅผ ์ํ๋ ๋งํผ ์ฌ๋ฌ ๋ฒ ํธ์ถํด๋ ํญ์ ๊ฐ์ ๊ฐ์ ๋๋ ค๋ฐ์ ์ ์๋ค.
var promise = doSomething();
promise.then(function(value) {
console.log('Got a value:', value);
});
promise.then(function(value) {
console.log('Got the same value again:', value);
});
์ด ์ํฐํด์์ ๊ตฌํํ Promise๋ ์๋ฒฝํ์ง๋ ์๋ค. ์๋ฅผ ๋ค์ด, ๋ง์ฝ resolve()๊ฐ ํธ์ถ๋๊ธฐ ์ ์ ์ฌ๋ฌ ๋ฒ then()์์ ํธ์ถํ๋ฉด ๋ง์ง๋ง์ ํธ์ถํ then()๋ง ์ฌ์ฉ๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ํ๊ฐ์ง ๋ฐฉ๋ฒ์ callback์ ๋ฐฐ์ด๋ก ์ ์ง(deferreds)ํ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฌ๋ ์ฌ๊ธฐ์์๋ ๊ตฌํ์ ์๊ณ Promise์ ๊ฐ๋ ์ ์๊ฐํ๋๋ฐ ์ฝ๋๋ฅผ ๊ฐ๋ฅํ ํ ๋จ์ํ๊ฒ ํ๋ ค๋ ๋ชฉ์ ์ด ์๋ค. ์ง๊ธ๊น์ง ๊ตฌํ์ผ๋ก๋ Promise๋ฅผ ์ค๋ช ํ๊ธฐ ์ํด ์ถฉ๋ถํ๋ค.
Promise ๋ฉ์๋ ์ฒด์ธ
Promise๋ ๊ฐ์ฒด์ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฐ์ ์ ์งํ๊ณ ์๊ธฐ ๋๋ฌธ์, ๋ฉ์๋๋ฅผ ์ฒด์ธํ๊ฑฐ๋, map์ฒ๋ฆฌ๋ฅผ ํ๊ฑฐ๋, ๋ณ๋ ฌ ํน์ ์์ฐจ์ ์ผ๋ก ์ฌ๋ฌ์ข ๋ฅ์ ์ผ์ ์ํํ ์ ์๋ค. ๋ค์ ์ฝ๋๋ Promise์ ๋ํ์ ์ธ ์ฌ์ฉ ์ฌ๋ก์ด๋ค.
getSomeData()
.then(filterTheData)
.then(processTheData)
.then(displayTheData);
getSomeData()๋ ์ฆ์ then() ํธ์ถ์ด ๋์๋์ง ์ ์ ์์ด์ ํด๋น Promise๋ฅผ ๋ฐํํ๋ค. ๊ทธ๋ฌ๋, ์ฒซ๋ฒ์งธ then()์ ํธ์ถ ๊ฒฐ๊ณผ๋ Promise๋ฉฐ, ๊ทธ ๋ฐํ๊ฐ์ ์ฌ์ฉํด ๋ค์ then()์ ํธ์ถํ๋ค.(๊ทธ ๋ค์๋ ๋ง์ฐฌ๊ฐ์ง๋ค). then()์์ Promise๋ฅผ ๋ฐํํ์ฌ ๋ฌด์จ์ผ์ด ์ผ์ด๋๋์ง ์์ ์์ด ๋ ๋ง์ ์ ๋ณด๋ฅผ ์ป์ ์ ์๋ค. ๊ทธ๊ฒ์ด ๋ฉ์๋ ์ฒด์ธ์ ์ฌ์ฉํ๊ณ ์๋ค๋ ๊ฒ์ด๋ค.
then()์ ๋ฐ๋์ Promise๋ฅผ ๋ฐํํ๋ค.
์ฌ๊ธฐ์ ์ฐ๋ฆฌ Promise ํด๋์ค์ ํจ๊ป ๋ฉ์๋ ์ฒด์ธ์ ์ถ๊ฐํ์.
function Promise(fn) {
var state = 'pending';
var value;
var deferred = null;
function resolve(newValue) {
value = newValue;
state = 'resolved';
if(deferred) {
handle(deferred);
}
}
function handle(handler) {
if(state === 'pending') {
deferred = handler;
return;
}
if(!handler.onResolved) {
handler.resolve(value);
return;
}
var ret = handler.onResolved(value);
handler.resolve(ret);
}
this.then = function(onResolved) {
return new Promise(function(resolve) {
handle({
onResolved: onResolved,
resolve: resolve
});
});
};
fn(resolve);
}
ํด. ์ฝ๊ฐ ์ฝ๋๊ฐ ์กฐ๊ธ ๋ณต์กํด์ก๋ค. ์ฐ๋ฆฌ๊ฐ ์ฒ์ฒํ ๊ตฌ์ถํ๋ ๊ฒ์ด ๊ธฐ์์ง ์๋ํ๊ฐ? ์ฌ๊ธฐ์ ์ค์ํ ํค๋ then()์ด ์๋ก์ด Promise๋ฅผ ๋ฐํํ๋ค๋ ๊ฒ์ด๋ค.
then()์ ํญ์ ์๋ก์ด Promise๊ฐ์ฒด๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ํ๋ ์ด์์ ์ฌ๋ฌ Promise๊ฐ์ฒด(created, resolved, ignored ๋๋)๊ฐ ์์ ์ ์๋ค. ์ด๊ฒ์ ๊ฐ์ฒด์ ๋ญ๋น์ฒ๋ผ ๋ณด์ผ์ ์๋ค. Callback ๊ธฐ๋ฒ์์๋ ์ด๊ฒ์ ๋ฌธ์ ๊ฐ ๋์ง ์๋๋ค. ๋ค๋ฅธ ํํธ์ผ๋ก Promise๊ฐ ๋นํ์ ๋ฐ์ ์ ์๋ ์ค์ํ ์์๊ฐ ๋๋ค. ๊ทธ๋ฌ๋ ๋ช๋ช JavaScript ์ปค๋ฎค๋ํฐ์์๋ ์ด๋ฐ ์ ์ผ๋ก ์ธํด Promise๋ฅผ ๊บผ๋ฆฌ๋ ํํ๋ฅผ ์ทจํ์ง ์๊ณ , ์ ๋๋ก ์ ๊ทผํ๊ธฐ ์์ํ๋ค.
๋๋ฒ์งธ Promise๊ฐ ํด๊ฒฐํด์ผํ๋ ๊ฒ์ ๋ฌด์์ธ๊ฐ? ๊ทธ๊ฒ์ ์ฒซ๋ฒ์งธ Promise๊ฐ ๋ฐํํ๋ ๊ฐ์ ๋ฐ๋ ๊ฒ์ด๋ค. ์ฆ,๋๋ฒ์งธ Promise๋ ์ฒซ๋ฒ์งธ ๋ฐํ ๊ฐ์ ์ธ์๋ก ๋ฐ๋๋ค. ์ด๊ฒ์ handle() ํ๋ฐ ๋ถ๋ถ์ ๊ตฌํ๋์ด ์์ผ๋ฉฐ, handler ๊ฐ์ฒด๋ resolve()์ ๋ํ ์ฐธ์กฐ์ onResolved์ callback์ ๋ํ ์ฐธ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ๊ฑฐ๊ธฐ์๋ resolve()์ ๋ณต์ฌ๋ณธ์ ๊ฐ์ง๊ณ ์๊ณ ๊ฐ Promise๋ค์ ์์ ์ resolve()๋ฅผ ๋ณต์ฌํ๊ฑฐ๋ ๋ด๋ถ์์ ์คํ ํด๋ก์ ๋ฅผ ๊ฐ๋๋ค. ์ด๊ฒ์ด ์ฒซ๋ฒ์งธ Promise์ ๋๋ฒ์งธ Promise์ ๋ค๋ฆฌ๋ค. ์ฒซ๋ฒ์งธ Promise๋ฅผ ๋ค์ ์ฝ๋์์ ํด๊ฒฐํ๋ค.
var ret = handler.onResolved(value);
์ด ์์ ์์๋ handler.onResolved๋ ๋ค์๊ณผ ๊ฐ๋ค.
function(value) {
console.log("Got a value:", value);
}
๋ค๋ฅด๊ฒ ๋งํ๋ฉด, ์ด์ฐํ๋ฉด ์ด๊ฒ์ด ์ฒซ๋ฒ์งธ ํธ์ถ๋ก then()์ ์ ๋ฌ๋๋ ํ๋ก์ธ์ค๋ค. ์ฒซ๋ฒ์งธ handler ๋ฐํ ๊ฐ์ด ๋๋ฒ์งธ Promise๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค. ์ด์ ๋ฉ์๋ ์ฒด์ธ ๊ตฌํ์ด ์์ฑ๋์๋ค.
doSomething().then(function(result) {
console.log('first result', result);
return 88;
}).then(function(secondResult) {
console.log('second result', secondResult);
});
// the output is
//
// first result 42
// second result 88
doSomething().then(function(result) {
console.log('first result', result);
// not explicitly returning anything
}).then(function(secondResult) {
console.log('second result', secondResult);
});
// now the output is
//
// first result 42
// second result undefined
then()์ ํญ์ ์๋ก์ด Promise๊ฐ์ฒด๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์ํ๋๋งํผ ๋ฉ์๋ ์ฒด์ธ์ ์ฐ๊ฒฐํ ์ ์๋ค.
doSomething().then(function(result) {
console.log('first result', result);
return 88;
}).then(function(secondResult) {
console.log('second result', secondResult);
return 99;
}).then(function(thirdResult) {
console.log('third result', thirdResult);
return 200;
}).then(function(fourthResult) {
// on and on...
});
๋ง์ฝ ์์ ์ฝ๋์์ ๋ง์ง๋ง์์ ๋ชจ๋ ์ฒ๋ฆฌ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ ์ด๋ป๊ฒํ๋ฉด ๋ ๊น? ๋ฉ์๋ ์ฒด์ธ์ ์ฌ์ฉํ์ฌ ํ์์ ๋ฐ๋ผ ์ฐ๋ฆฌ ์ค์ค๋ก๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋งค๋ด์ผํ๊ฒ ์ ๋ฌํ ํ์๊ฐ ์๋ค.
doSomething().then(function(result) {
var results = [result];
results.push(88);
return results;
}).then(function(results) {
results.push(99);
return results;
}).then(function(results) {
console.log(results.join(', ');
});
Promise๋ ํญ์ ํ๋์ ๊ฐ์ ํด๊ฒฐํ๋ค. ๋ง์ฝ ๋ ๊ฐ ์ด์์ ๊ฐ์ ์ ๋ฌํ๋ ค๋ฉด ์ฌ๋ฌ ๊ฐ์ ์ฒ๋ฆฌํ ์ ์๋ ๊ฒ๋ค(๋ฐฐ์ด, ๊ฐ์ฒด, ๊ฒฐํฉ๋ ๋ฌธ์์ด ๋ฑ)์ ์ด์ฉํด์ผ ํ๋ค.
Promise๋ฅผ ๋ ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ Promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ all() ๋ฉ์๋๋, ๋ง์ ๋ค๋ฅธ Utility ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด Promise์ ์ ์ฉ์ฑ์ ๋ ์ข์์ง๋ค. ๋ฌด์์ ์ฌ์ฉ ํ๋๊ฐ๋ ๋ ์ ์ฌ๋ฌ๋ถ์ ์ทจํฅ์ ๋ง๊ฒ ์ ํํ๋ฉด ๋๋ค.
Callback์ ์ ํ์ฌํญ์ด๋ค.
then()์ ์ง์ ๋ callback์ ์๋ฐํ ํ์ ์ฌํญ์ ์๋๋ค. ๋ง์ฝ callback์ ์์ด์ ๊ฒฝ์ฐ Promise๋ ์ด์ Promise๊ณผ ๊ฐ์ ๊ฐ์ ์ฒ๋ฆฌํด ์ค๋ค.
doSomething().then().then(function(result) {
console.log('got a result', result);
});
// the output is
//
// got a result 42
์ด๋ฏธ ๊ตฌํ๋ handle()์ ๋ด์ฉ์ ๋ณด๋ฉด callack์ด ์๋ ๊ฒฝ์ฐ์๋ Promise๋ฅผ resolveํ๊ณ ์ฒ๋ฆฌ๋ฅผ ์ข ๋ฃํ๋๋ก ๋์ด์๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
if(!handler.onResolved) {
handler.resolve(value);
return;
}
๋ฉ์๋ ์ฒด์ธ ๋ด์์ Promise ๋ฐํ
์ฐ๋ฆฌ์ ์ฒด์ธ ๊ตฌํ ๋ฐฉ๋ฒ์ ์ฝ๊ฐ ์ ๊ตํ์ง ๋ชปํ ๋ถ๋ถ์ด ์๋ค. ์ฐ๋ฆฌ์ resolve๋ ๊ฐ์ ๋ํด ์๋ฌด๊ฒ๋ ํ์ธํ์ง ์๊ณ ๋ค์ ์์ ์ ๊ทธ๋๋ก ์ ๋ฌํ๋ค. ๋ง์ฝ resolve๋ ๊ฐ ํ๋๊ฐ Promise ๊ฐ์ฒด์ด๋ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ด๋ค.
doSomething().then(result) {
// doSomethingElse returns a promise
return doSomethingElse(result)
}.then(function(finalResult) {
console.log("the final result is", finalResult);
});
์ด ์ฝ๋๋ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๋๋ก ์์ง์ด์ง ์๋๋ค. finalResult์๋ resolve๋ ๊ฐ์ด ์๋๋ผ Promise ๊ฐ์ฒด๊ฐ ์ ๋ฌ๋๋ค. ์๋๋ ๊ฒฐ๊ณผ๊ฐ์ ์ป๊ธฐ์ํด ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ์ ์์ ํด์ผ ํ๋ค.
doSomething().then(result) {
// doSomethingElse returns a promise
return doSomethingElse(result)
}.then(function(anotherPromise) {
anotherPromise.then(function(finalResult) {
console.log("the final result is", finalResult);
});
});
์ฝ๋๊ฐ ๊ฝค ๋ณต์กํ๊ฒ ๋์๋ค. ์ด ์๋ฃจ์ ์ Promise์ ๊ตฌํ์ ๋ณ๊ฒฝํ์ฌ resolve๋ ๊ฐ์ด Promise ๊ฐ์ฒด์ธ์ง ํธ์ถ์๊ฐ ์์ํ์ง ์๊ณ ์ฒ๋ฆฌํ ์ ์๋๋ก ํ๋ค. ์ด๊ฒ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋๋ฐ resolve()์ ์ ๋ฌ ๋ ๊ฐ์ด Promise๊ฐ์ฒด์ธ ๊ฒฝ์ฐ์ ํน๋ณํ ์ฒ๋ฆฌ๊ฐ ์ถ๊ฐ๋์์ ๋ฟ์ด๋ค.
function resolve(newValue) {
if(newValue && typeof newValue.then === 'function') {
newValue.then(resolve);
return;
}
state = 'resolved';
value = newValue;
if(deferred) {
handle(deferred);
}
}
Promise๋ฅผ ์์ ํ์ ๊ฒฝ์ฐ resolve()๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๊ณ์ ํธ์ถํ๊ฒ ๋๋ค. ํ์ ์ด Promise๊ฐ ์๋๋ฉด ๊ทธ ์์ ์์ ์ฒ๋ฆฌ๋ฅผ ๋ค์์ผ๋ก ์งํํ๋ค.
์ด๋ฐ ๊ฒฝ์ฐ์๋ ๋ฌดํ ๋ฃจํ๊ฐ ๋ ๊ฐ๋ฅ์ฑ์ด ์๋ค. Promise/A+ ์คํ์ ํ์ ์ฌํญ์ ์๋์ง๋ง ๋ฌดํ ๋ฃจํ๋ฅผ ํด๊ฒฐํ ์ ์๋ ํํ๋ก ๊ตฌํํ๋ ๊ฒ์ ์ถ์ฒํ๊ณ ์๋ค.
๋ํ ์ฌ๊ธฐ์์ ์๊ฐํ๋ ๊ตฌํ์ฒด๋ ์คํ์ ์ถฉ์กฑํ์ง๋ ์์๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก ์ด ์ํฐํด์์ ์๊ฐํ ๊ตฌํ์ฒด๋ ์คํ์ ์ถฉ์กฑํ๋ ๊ฒ์ ์๋๋ค. ์ฌ๊ธฐ์ ๋ํด ์ข ๋ ํธ๊ธฐ์ฌ์ ๊ฐ์ง๊ณ ์๋ค๋ฉด Promise resolution procedure๋ฅผ ์ฝ๋ ๊ฒ์ ์ถ์ฒํ๋ค.
์ฃผ๋ชฉํ ๋งํ ๊ฑด, newValue๊ฐ Promise๊ฐ์ฒด์ธ์ง ์ฌ๋ถ์ ํ์ ์ด ๋์จํ๊ฒ ์ฒดํฌ๋ฅผ ํ๋ ๊ฑด ์๋๊น? ์ฌ๊ธฐ์ then() ํจ์๊ฐ ์๋์ง๋ง ํ์ธํ๋ค. ์ด ๋ ํ์ดํ(๋์ ํ์ดํ์ ํ ์ข ๋ฅ๋ก, ๊ฐ์ฒด์ ๋ณ์ ๋ฐ ๋ฉ์๋์ ์งํฉ์ด ๊ฐ์ฒด์ ํ์ ์ ๊ฒฐ์ ํ๋ ๊ฒ)์ ์๋์ ์ธ ๊ฒ์ด๋ค. ์๋์ ์ผ๋ก ๋ชจํธํ๊ฒ ํ ๊ฒ์ผ๋ก, Promise์ ๊ตฌํ์ฒด๊ฐ ์๋ก ์กฐ๊ธ ๋ค๋ฅธ 3rd Party ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ์ ์ํธ๊ฐ์ ์กฐํฉ๋ ์๋ก Promise์ด๋ผ๊ณ ํด์ํ ์ ์๊ฒ ๋๋ค.
์คํ์ ์ ์ ํ๊ฒ ๋ฐ๋ฅธ๋ค๋ฉด ์ฌ๋ฌ Promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์๋ก ์กฐํฉํ ์ ์๋ค.
์ฌ๊ธฐ์ ๋ฉ์๋ ์ฒด์ด๋๊ณผ ํจ๊ป Promise ๊ตฌํ์ฒด๋ ์์ฃผ ์๋ฒฝํ๋ค. ํ์ง๋ง ์๋ฌ ํธ๋ค๋ง ๋ถ๋ถ์ ๋ฌด์๋์ด ์๋ ๊ฒ์ ์์ ๋์์ผ๋ฉด ํ๋ค.
Promise ๊ฑฐ๋ถํ๊ธฐ
Promise๊ฐ ์ฒ๋ฆฌ๋๋ ๋์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค๋ฉด ์ฌ์ ์ ํจ๊ป ๊ฑฐ๋ถ(reject)ํด์ผ ํ๋ค. ๊ฑฐ๋ถ๋ ๊ฒฝ์ฐ์ ํธ์ถ์๋ ์ด๋ป๊ฒ ์ ์ ์์๊น? ๊ทธ๊ฒ์ then()์ ๋๋ฒ์งธ ์ฝ๋ฐฑ ์ธ์์ ์ค๋ฅ ๋ฐ์์์ ์ฒ๋ฆฌ๋ฅผ ์ ๋ฌํ์ฌ ์ค๋ฅ ์๋ฆผ์ ์์์ฐจ๋ฆด ์ ์๋ค.
doSomething().then(function(value) {
console.log('Success!', value);
}, function(error) {
console.log('Uh oh', error);
});
์์์ ์ธ๊ธํ ๋ฐ์ ๊ฐ์ด, Promise ์ํ๋ pending์์ resolved, ๋๋ rejected ์ค ํ๋์ ์ํ๋ก ์ ํํ๋ค. ๊ฒฐ์ฝ ๋ ์ํ๊ฐ ๋ ์ ์๋ค. ๋ค๋ฅธ๋ง๋ก ํ๋ค๋ฉด, ์์ 2๊ฐ์ ์ฝ๋ฐฑ ์ค ํ๋๋ง ํธ์ถํ๋ ๊ฒ์ด๋ค.
Promise๊ฐ reject()์ ์คํํ์ฌ rejected๋ฅผ ํ์ฑํํ ์ ์์ด, reject()๋ผ๋ ํจ์๋ resolve()์ฒ๋ผ ์ค์ํ ๊ธฐ๋ฅ์ ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์๋์ doSomething()์์ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ถ๊ฐ ๋์๋ค.
function doSomething() {
return new Promise(function(resolve, reject) {
var result = somehowGetTheValue();
if(result.error) {
reject(result.error);
} else {
resolve(result.value);
}
});
}
Promise ๊ตฌํ์ฒด ๋ด๋ถ์๋ ๊ฑฐ๋ถ ๊ธฐ๋ฅ์ด ํ์ํ๋ค. Promise๊ฐ reject๋๋ฉด ๊ทธ ์ดํ์ ๋ชจ๋ Promise๋ ๊ฑฐ๋ถ๋ ํ์๊ฐ ์๋ค.
๊ทธ๋ผ ๋ค์ Promise ์ ์ฒด์ ๋ํ ๊ตฌํ์ฒด๋ฅผ ๋ณด์. ์ด๋ฒ์๋ reject ๊ธฐ๋ฅ์ด ์ถ๊ฐ ๋์๋ค.
function Promise(fn) {
var state = 'pending';
var value;
var deferred = null;
function resolve(newValue) {
if(newValue && typeof newValue.then === 'function') {
newValue.then(resolve, reject);
return;
}
state = 'resolved';
value = newValue;
if(deferred) {
handle(deferred);
}
}
function reject(reason) {
state = 'rejected';
value = reason;
if(deferred) {
handle(deferred);
}
}
function handle(handler) {
if(state === 'pending') {
deferred = handler;
return;
}
var handlerCallback;
if(state === 'resolved') {
handlerCallback = handler.onResolved;
} else {
handlerCallback = handler.onRejected;
}
if(!handlerCallback) {
if(state === 'resolved') {
handler.resolve(value);
} else {
handler.reject(value);
}
return;
}
var ret = handlerCallback(value);
handler.resolve(ret);
}
this.then = function(onResolved, onRejected) {
return new Promise(function(resolve, reject) {
handle({
onResolved: onResolved,
onRejected: onRejected,
resolve: resolve,
reject: reject
});
});
};
fn(resolve, reject);
}
reject()์ ์ถ๊ฐํ๋ ๊ฒ ์ธ์๋, handle() ์์๋ reject๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค. handle()๋ด์์ reject ํจ์ค์ resolve ํจ์ค๋ state ๊ฐ์ ์ํด ๊ฒฐ์ ๋๋ค. ์ด state ๊ฐ์ ๋ค์ Promise์ ์ ๋ฌ๋๊ณ ๋ค์ Promise์์ ๋ฐ์ state์ ๊ฐ์ ๋ฐํ์ผ๋ก, reject()์ resolve()๋ฅผ ํธ์ถํ๋ฉฐ ์์ ์ state ๊ฐ์ผ๋ก ๋ฐ์ state ๊ฐ์ ์ค์ ํ๋ค.
Promise๋ฅผ ์ฌ์ฉํ ๋ ์ค๋ฅ ์ฝ๋ฐฑ์ ์๋ตํ๊ธฐ ์ฝ๋ค. ๊ทธ๋ฌ๋ ์ค๋ฅ ์ฝ๋ฐฑ์ ์๋ตํ ๊ฒฝ์ฐ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋ ๊ทธ๊ฒ์ ์ฐพ์๊ฐ ์ ์๋ค. ์ ์ด๋ ์ฒด์ธ๋ ๋ง์ง๋ง Promise์ ์๋ฌ ์ฝ๋ฐฑ์ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ค. ๋์ค์ ์ข ๋ ์์ธํ ๋ด์ฉ์ ๋ค๋ฃฐ ๊ฒ์ด๋ค.
์๊ธฐ์น ์์ ์ค๋ฅ๋ reject์ ์ฐ๊ฒฐ๋์ด์ผ ํ๋ค.
์ง๊ธ๊น์ง ์๋ฌ ํธ๋ค๋ง์ ์๋ ค์ง ์ค๋ฅ๋ง์ ๋์์ผ๋กํ๊ณ ์์๋ค. ๊ทธ๋์ ์์๋์ง ์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ์๋ ๋ชจ๋ ๊ฒ ํ๋ฉธ๋ ๊ฒ์ด๋ค.Promise์ ๊ตฌํ์ฒด๋ ์๊ธฐ์น ์์ ์์ธ๋ฅผ ์บ์นํ๊ณ ์ ์ ํ๊ฒ rejectํ๋ ๊ฒ์ด ํ์์ ์ด๋ค.
์ด๊ฒ์ด resolve() ๋ฉ์๋๋ try/cach ๋ธ๋ก์ผ๋ก ์์์ธ์ผ ํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
function resolve(newValue) {
try {
// ... as before
} catch(e) {
reject(e);
}
}
๋ํ ๋ง์ฐฌ๊ฐ์ง๋ก ์ค์ํ ์ ์ ํธ์ถ์๊ฐ ์ง์ ํ ์ฝ๋ฐฑ์ด ์์์น ๋ชปํ ์์ธ๋ฅผ ๋์ง์ง ์์ ์๋ ์๋ค. ์ด ์ฝ๋ฐฑ์ handle()์์ ํธ์ถ๋๋๋ฐ ๋ค์๊ณผ ๊ฐ์ด ํด๊ฒฐํ๋ค.
function handle(deferred) {
// ... as before
var ret;
try {
ret = handlerCallback(value);
} catch(e) {
handler.reject(e);
return;
}
handler.resolve(ret);
}
Promise๋ ์ค๋ฅ๋ฅผ ๋จน์ด๋ฒ๋ฆด ์ ์๋ค.
Promise ๋ํ ์ดํด๊ฐ ์ ๋ชปํ๋ฉด ์๋ฌ๋ฅผ ์์ ํ ๋ฌต์ดํด ๋ฒ๋ฆฌ๋ ๊ตฌํ์ ํ ๊ฐ๋ฅ์ฑ์ด ์๋ค. ๋ง์ ์ฌ๋๋ค์ด ๊ฒช์ ์ ์๋ ๊ฒ์ด๋ค.
๋ค์ ์๋ฅผ ์๊ฐํด ๋ณด์.
function getSomeJson() {
return new Promise(function(resolve, reject) {
var badJson = "uh oh, this is not JSON at all!";
resolve(badJson);
});
}
getSomeJson().then(function(json) {
var obj = JSON.parse(json);
console.log(obj);
}, function(error) {
console.log('uh oh', error);
});
๋ฌด์จ ์ผ์ด ์ผ์ด๋ ๊น? then()์ ์ฝ๋ฐฑ ์ธ์๋ ์ฌ๋ฐ๋ฅธ ํ์์ JSON์ ๋ฐ์ ๊ฒ์ ์์ํ๋ค. ์ฝ๋ฐฑ์์ ๋ฐ์ ๊ฐ์ ํ์ธํ์ง ์๊ณ JSON ํ์ฑํ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๊ฐ ์ค๋ฅ๊ฐ์์ ๊ฒฝ์ฐ์ ๋๋นํ์ฌ then()์ ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ์ ์ค๋ฅ ์ฝ๋ฐฑ์ ์ง์ ํ๋ค. ์ด๋ ๊ฒ ๊ตฌํํ๋ฉด ์๋๋๋ก ์๋ฌ ์ฝ๋ฐฑ์ด ํธ์ถ๋๋ ๊ฒ์ผ๊น?
์๋๋ค. ์ค๋ฅ ์ฝ๋ฐฑ์ ํธ์ถ๋์ง ์๋๋ค. ์์ fiddle ์์ ๋ฅผ ์คํํด ๋ณด๋ฉด ์๋ฌด๊ฒ๋ ์ถ๋ ฅํ์ง ์๋๋ค๋ ๊ฒ์ ์ ์ ์๋ค. ๋ฑ๊ณจ์ด ์๋ํด์ง๋ค.
์ ๊ทธ๋ ๊ฒ ๋ ๊น? ์ด๊ฒ์ ์๊ธฐ์น ์์ ์ค๋ฅ(JSON ํ์ฑ์ ์คํจํ ์์ธ)๋ handle()๋ด์์ ์บ์น๋์ง๋ง, JSON ํ์ฑ ์ฒ๋ฆฌ๊ฐ ํธ์ถ๋ ๋์๋ ๋์ Promise๋ ์ด๋ฏธ resolved ์ํ์ด๊ธฐ ๋๋ฌธ์ reject๊ฐ ํธ์ถ๋์ง ์๋๋ค. ์์ธ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ์๋ ๋ค์ Promise๊ฐ reject๋๋ค.
ํญ์ ๊ธฐ์ตํ๋ผ. then()์ฝ๋ฐฑ ์์, Promise๋ ์ด๋ฏธ resolved ์ํํ๋ ๊ฒ์ด๋ค. ์ฝ๋ฐฑ์ ๊ฒฐ๊ณผ๊ฐ ๋ฌด์์ด๋ Promise์ ์ํฅ์ ์ฃผ์ง ์๋๋ค.
๋ง์ฝ ์์ ์ค๋ฅ๋ฅผ ์ผ์นํ๋ ค๋ฉด ์ค๋ฅ ์ฝ๋ฐฑ์ ๋ค์ then()์์ ์ง์ ํด์ผ ํ๋ค.
getSomeJson().then(function(json) {
var obj = JSON.parse(json);
console.log(obj);
}).then(null, function(error) {
console.log("an error occured: ", error);
});
์ด์ ์ค๋ฅ ๋ก๊ทธ๋ฅผ ์ ๋๋ก ๊ธฐ๋ก ํ ์ ์๋ค.
๋ด ๊ฒฝํ์,์ด ์ ์ด Promise์ ๊ฐ์ฅ ํฐ ํจ์ ์ด๋ค. ๋ ๋์ ํด๊ฒฐ์ฑ ์ ์ํด์๋ ๋ค์ ์น์ ์ ์ฝ์ด๋ผ.
done()์ ๊ตฌ์ ์ฉ์ผ๋ก ์ฌ์ฉํ์
(์ ๋ถ๋ ์๋์ง๋ง) ๋๋ถ๋ถ์ Promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ done() ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ์ด๊ฒ์ then()๊ณผ ๋งค์ฐ ๋น์ทํ์ง๋ง, done()์ ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก ์์์ ๋งํ๊ฒ์ฒ๋ผ then()์ ํจ์ ์ ํผํ ์ ์๋ค. done()์ then()์ด ํธ์ถ๋๋ ๊ณณ์์๋ ์ธ์ ๋ผ๋ ํธ์ถ ํ ์ ์๋ค. ๊ฐ์ฅ ํฐ ์ฐจ์ด๋ done()์ Promise๋ฅผ ๋ฐํํ์ง ์๋๋ค๋ ๊ฒ์ด๋ค. ๋ํ done()๋ด์์ ๋ฐ์ํ ์ด๋ ํ ์์ธ๋ Promise ๊ตฌํ์ฒด์์ ์บ์น๋์ง ์๋๋ค. ๋ค๋ฅธํํธ์ผ๋ก, done()์ Promise ์ฒด์ธ์ด ๋ชจ๋ resolved๋์์ ๋ ํธ์ถํ๋ ๊ฒ์ด๋ค. getSomeJson() ์์ ๋ done()์ ์ฌ์ฉํด ์ข ๋ ์์ ํ ๊ตฌํ์ฒด๊ฐ ๋ ์ ์๋ค.
getSomeJson().done(function(json) {
// when this throws, it won't be swallowed
var obj = JSON.parse(json);
console.log(obj);
});
done()์ ์ค๋ฅ ์ฝ๋ฐฑ์ ์ง์ ํ ์ ์์ผ๋ฉฐ, then()๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก done(callback, errback)๋ผ๋ ์ํ๋ก ์ง์ ํ ์๋ ์๋ค. ์ค๋ฅ ์ฝ๋ฐฑ(errback)์ด Promise ์์ ์ด ์์ ํ ์ข ๋ฃํ๊ณ ํธ์ถ๋๋ฏ๋ก Promise๋ฅผ ์ด์ฉํ ์ผ๋ จ์ ์ฒ๋ฆฌ์์ ๋ฐ์ํ ์ด๋ ํ ์ค๋ฅ๋ ์บ์นํ ์ ์๋ค.
done()์ (์ ์ด๋ ๋น๋ถ๊ฐ์) Promise/A+์ ์คํ์ด ์๋๋ฏ๋ก, Promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ํด ๊ตฌํ๋์ง ์์ ์๋ ์๋ค.
Promise์ ์ข ๋ฃ๋ ๋น๋๊ธฐ๊ฐ ํ์ํ๋ค.
์ด ์ํฐํด์ ์ด๊ธฐ์ setTimeout์ ์ฌ์ฉํด ์ฝ๊ฐ์ ์์์๋ฅผ ์ผ๋ค. ๊ทธ๋ฐ ๋ค์ ํดํน ์ํ์ผ๋ก ์ด๋ฅผ ์์ ํ์ฌ setTimeout์ ์ฌ์ฉํ์ง ์์๋ค. ๊ทธ๋ฌ๋ ์ค์ ๋ก Promise/A+์ ์คํ์ Promise ์ข ๋ฃ๋ ๋น๋๊ธฐ์ ์ผ๋ก ์ด๋ฃจ์ด์ง๋ค. ์ด ์คํ์ ์๊ตฌ์ฌํญ์ ์ถฉ์กฑํ๊ธฐ ์ํด handle() ํจ์ ๊ตฌํ์ ๋๋ถ๋ถ์ setTimeout ํธ์ถ๋ก ๊ฐ์ ํ์๊ฐ ์๋ค.
function handle(handler) {
if(state === 'pending') {
deferred = handler;
return;
}
setTimeout(function() {
// ... as before
}, 1);
}
Promise/A+ ํ์ํ ๊ตฌํ์ ์ด์์ด ์ ๋ถ๋ค. ์ฌ์ค, ๋ง์ Promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋น๋๊ธฐ๋ฅผ ์ง์ํ๊ธฐ ์ํด setTimeout์ ์ฌ์ฉํ์ง ์๋๋ค. ๋ง์ฝ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ NodeJS์์ ์๋ํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด process.nextTick์ ์ฌ์ฉํ ๊ฒ์ด๊ณ , ๋ง์ฝ ๋ธ๋ผ์ฐ์ ์์ ์๋ํ๋ ๊ฒฝ์ฐ๋ฉด setImmediate๋ setImmediate shim(์ง๊ธ IE์์๋ง ์๋ํฉ๋๋ค)์ Kris Kowal์ asap(Kris Kowal์ Q๋ผ๋ ์ธ๊ธฐ์๋ Promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ) ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ง๋ ๋ชจ๋ฅธ๋ค.
์ ์ด๋ฌํ ๋น๋๊ธฐ ์๊ตฌ ์ฌํญ์ด ์คํ์ ์๋๊ฐ?
๋น๋๊ธฐ๋ฅผ ์ง์ํจ์ผ๋ก์จ ์ผ๊ด์ฑ๊ณผ ์ ๋ขฐํ ์ ์๋ ํ๋ฆ์ ์ ๊ณตํ ์ ์๋ค. ๋ค์์ ์ต์ง๋ก ๊พธ๋ฏผ ์๋ฅผ ์ดํด ๋ณด์.
var promise = doAnOperation();
invokeSomething();
promise.then(wrapItAllUp);
invokeSomethingElse();
์ด ๊ตฌํ์์ ์ฒ๋ฆฌ ์์๋ ์ด๋ป๊ฒ ๋ ๊น? ์ด๋ฆ์ ๊ธฐ๋ฐ์ผ๋ก ์ถ์ธกํด ๋ณด๋ฉด, invokeSomething() -> invokeSomethingElse() -> wrapItAllUp() ์์ผ๋ก ํธ์ถ ํ ์ ์๊ฒ ์ค๊ณ๋์ด ์๋ค. ๊ทธ๋ฌ๋ ์ด๋ฐ ์คํ ์์๋ Promise์ resolve ์ฒ๋ฆฌ๊ฐ ๋๊ธฐ์ ์ธ์ง ๋น๋๊ธฐ์ ์ผ๋ก ์ํ๋๋์ง์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค. ๋ง์ฝ, doAnOperation() ํจ์๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋๋ค๋ฉด ์์ ์์๋๋ก ์คํ ์์๊ฐ ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฌ๋ doAnOperation()์ด ๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋ ๊ฒฝ์ฐ invokeSomething() -> wrapItAllUp() -> invokeSomethingElse() ์์ผ๋ก ๋์ด ๊ฐ์ ํ ๊ฒ๊ณผ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ๋์ด ๋ฒ๋ฆฐ๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Promise๋ ํญ์ ๋น๋๊ธฐ์ ์ผ๋ก resolved ๋์ด์ผ ํ๋ค. ์ฌ์ง์ด ๋น๋๊ธฐ๊ฐ ์๋๋๋. Promise๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก resolved ๋จ์ผ๋ก์จ(ํฉ๋ฆฌ์ ์ธ ์ฝ๋์ ๋น์ ) Promise ์ด์ฉ์๋ Promise๊ฐ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๋์ํ๊ณ ์๋์ง ์ฌ๋ถ๋ฅผ ์๊ฐํ์ง ์์๋ ๋๋ค.
Promise๋ resolved๋๊ธฐ ์ํด์ ํ๋ฒ ์ด์์ ์ด๋ฒคํธ ๋ฃจํ(์์ ์ ์ฃผ ์ค๋ ๋์์ ๋ฃจํ)๊ฐ ํ์ํ๋ค. ์ด๊ฒ์ ํ์ค ์ฝ๋ฐฑ ์ ๊ทผ ๋ฐฉ์์ ํ์๋ ์๋๋ค.
then/promise ์ด์ผ๊ธฐ๋ฅผ ๋๋ด๊ธฐ ์ ์
์ธ์์๋ Promise ์คํ์ ๋ชจ๋ ์ถฉ์กฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ง์ด ์๋ค. ๊ทธ ์ค์์๋ then ํ์ promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋นํ ์ฌํํ๋ค. ๊ทธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ฐ๋จํ ๊ตฌํ ์คํ์ ์ถฉ์กฑํ๊ณ ์๊ณ ์คํ ์ด์ธ์ ๊ฒ์ ๊ตฌํํ์ง ์์๋ค. ๋ง์ฝ ๊ทธ ๊ตฌํ์ ๋ณผ ๊ธฐํ๊ฐ ์์ผ๋ฉด, ๊ทธ ๊ตฌํ์ด ์ฌ๊ธฐ์ ๋งค์ฐ ๋น์ทํ๋ค๋ ๊ฒ์ ์ ์ ์๋ค. thenํ์ promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ด ์ํฐํด์ ์ฐ๊ธฐ ์ํ ๊ธฐ๋ฐ์ด ๋์๊ณ , ์ฐ๋ฆฌ๋ ๊ฑฐ์ ๋น์ทํ ๊ตฌํ์ฒด๋ฅผ ์ฌ๊ธฐ ์ํฐํด์ ๊ตฌ์ถํ๋ค. ๊ฐ๋ฐ์์ธ Nathan Zadoks์ Forbes Lindsay์ ์๋ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋๋ถ์ JavaScript Promise๋ฅผ ์๋์ํฌ ์ ์์๋ค. ๋ํ Forbes Lindsay๋ promisejs.org ์ฌ์ดํธ๋ฅผ ์์ํ๋ค๊ณ ์ธ๊ธํ๋ค.
์ด ์ํฐํด์์ ๊ตฌํํ ๋ด์ฉ๊ณผ ์ค์ ๊ตฌํ์๋ ๋ช ๊ฐ์ง ์ฐจ์ด์ ์ด ์๋ค. ๊ทธ๊ฒ์ Promise/A+๋ ์ฌ๊ธฐ์ ๋ค๋ฃจ์ง ์๋ ๋ค๋ฅธ ์์ธํ ์คํ๋ค์ด ์ ์๋์ด ์๊ธฐ ๋๋ฌธ์ด๋ค. ๊ผญ Promise/A+ ์คํ ์ฝ์ด ๋ณด๊ธธ ๊ถํ๋ค. ๋ช ์ธ์๋ ๋น๊ต์ ์งง๊ณ ์ฝ๊ธฐ ์ฝ๋ค.
๊ฒฐ๋ก
๋๊น์ง ์ฝ์ด ์ฃผ์ ์ ๊ฐ์ฌํ๋ค. ์ง๊ธ๊น์ง Promise์ ํต์ฌ ๋ถ๋ถ์ ๋ค๋ค์๋ค. ๊ทธ๋ฆฌ๊ณ ๋ง์ Promise ๊ตฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ all() , race() , denodeify() ๋ฑ ๊ทธ ๋ฐ์๋ ๋ค์ํ ๊ธฐ๋ฅ๋ค์ด ์ ๊ณต๋๊ณ ์๋ค. Promise์ ๊ฐ๋ฅ์ฑ์ ์๊ธฐ์ํด์๋ API docs for Bluebird๋ฅผ ์ฝ๋ ๊ฒ์ด ์ข๋ค. ๋๋ Promise๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง, ๊ทธ๋ฆฌ๊ณ ๋ฌด์์ ํด๊ฒฐํ๋ ค๊ณ ํ๊ณ ์๋์ง๋ฅผ ์ดํดํ๊ณ ๋ถํฐ๋, Promise ์ ๋ง ์ข์ํ๊ฒ ๋์๋ค. Promise๋ ๋ด ํ๋ก์ ํธ ์ฝ๋๋ฅผ ๋งค์ฐ ๊ฐ๊ฒฐํ๊ฒ ๊ทธ๋ฆฌ๊ณ ์ฐ์ํ๊ฒ ํด์ค๋ค. ๋์ฑ ๋ํ๊ณ ์ถ์ ๋ง์ ์ด ๋ฌธ์๋ ์๋ฌธ์ ์ง๋์ง ์๋๋ค๋ ๊ฒ์ด๋ค.