๐ Chapter 6: ํ๋ผ๋ฏธ์ค ํจํด
๐ ๋จ์ ํ ์คํธโ
๐ ํ๋ก๋ฏธ์ค ์ฌ์ฉ๋ฒโ
5์ฅ์์ recordCheckIn
ํจ์์๋ checkInRecorder
๊ฐ์ฒด๊ฐ ์์๋ค. ํ์ง๋ง ๋จ์ ํ
์คํธ๋ฅผ ํ ๋๋ ์ฌ์ค๋ฏผ ์คํ์ด๊ฐ recordCheckIn
๋์ญ์ด์๊ณ , ์ด ์คํ์ด๋ ์ค์ง recordCheckIn
์ด ํธ์ถ๋์๋์ง๋ง ๊ฐ์ํ๋ค.
expect(checkInRecorder.recordCheckIn).toHaveCalledWith(attendee);
checkInService
๊ฐ checkInRecorder
๋ฅผ ํธ์ถํ๋ ๊ฑด ๋จ์ํ ์ ์ง๋ฌ ๋๊ณ ์์ด๋ฒ๋ฆฌ๊ธฐ(fire-and-forget)๋ผ ํธ์ถ ์ฌ๋ถ๋ง ์๋ฉด ๊ทธ๋ง์ด๋ค.
Conference.checkInService = function(checkInRecorder) {
// ์ฃผ์
ํ ใ
heckInRecorder์ ์ฐธ์กฐ๊ฐ์ ๋ณด๊ดํ๋ค.
var recorder = checkInRecorder;
return {
checkIn: function(attendee) {
attendee.checkIn();
recorder.recordCheckIn(attendee);
}
};
};
๊ทธ๋ฌ๋ ๋ ๋ง์ ์ผ์ ํ๊ณ ์ถ์ ๋๊ฐ ์๋ค(์, ์๋ฌ ์ฒ๋ฆฌ ๋๋ ์์
์ฑ๊ณต ์ ํ์ ์ฒ๋ฆฌ๋ฅผ ๋ง๋ถ์ด๋ ์์
). checkInRecorder
๋ ๋ณดํต XMLHttpRequest
๋ก ์ฒดํฌ์ธ ๋ฑ๋ก ์๋ฒ์ ์ฐ๋ํ ์ ์๊ฒ ๊ตฌํํ๋ค. checkInRecorder
๋ ์์ฒญ์ ๋ณด๋ธ ํ onreadystatechange
์ด๋ฒคํธ๋ฅผ ๊ท ๊ธฐ์ธ์ด๊ณ ์๋ค๊ฐ ๊ฒฐ๊ณผ์ ์ฑ๊ณต/์คํจ์ ๋ฐ๋ผ ์กฐ์น๋ฅผ ํ ๋ค ์์ ์ ํธ์ถ๋ถ (checkInService
)์ ๋ฐํต์ ๋๊ธฐ๋ ์์ผ๋ก ํ๋ฌ๊ฐ๋ค. ์ด๋ ๊ฒ ํ์ ๋ฐํ ์์
์ ๊ณ์ ์ ๊ฒฝ ์ฐ๋ ๊ฑด ๋ฐ๋ถํ ์ผ์ด๊ณ ์์นซ ๋์ฝํ ์ฝ๋๋ก ๋ค๋ฒ๋ฒ
๋ ์ฐ๋ ค๋ ์๋ค. ๋ค์์ฒ๋ผ ๋ญ๊ฐ ์์๊ณ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ ์ ์์๊น?
Conference.checkInService = function(checkInRecorder) {
'use strict';
// ์ฃผ์
ํ ใ
heckInRecorder์ ์ฐธ์กฐ๊ฐ์ ๋ณด๊ดํ๋ค.
var recorder = checkInRecorder;
return {
checkIn: function(attendee) {
attendee.checkIn();
recorder.recordCheckIn(attendee).then(
// ์ฑ๊ณต
attendee.setCheckInNumber,
// ์คํจ
attendee.undoCheckIn,
);
}
};
};
recordCheckIn
๋ก์ง์ ๋น๋๊ธฐ ์ฒ๋ฆฌํ ๋ค์(์ด๋ then
์ ํธ์ถ), ๊ทธ ๊ฒฐ๊ณผ์ ์ฑ๊ณต/์คํจ์ ๋ฐ๋ผ ์ง์ ๋ ์ฝ๋ฐฑ์ ๋ถ๋ฅธ๋ค. ์ด๋ฌํ ์๊ฑด์ ๋จ์ ํ
์คํธ๋ก 5์ฅ์ ๋จ์ํ
์คํธ์์ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํด์ค๋ค.
describe('Conference.checkInService', () => {
'use strict';
var checkInService, checkInRecorder, attendee;
beforeEach(() => {
checkInRecorder = Conference.checkInRecorder();
checkInService = Conference.checkInService(checkInRecorder);
attendee = Conference.attendee('ํ์ฒ ', '์');
});
describe('checkInService.checkIn(attendee)', () => {
describe('checkInRecorder ์ฑ๊ณต ์', () => {
var checkInNumber = 1234;
beforeEach(() => {
spyOn(checkInRecorder, 'recordCheckIn')
.and
.callFake(() => Promise.resolve(checkInNumber));
});
it('์ฐธ๊ฐ์๋ฅผ ์ฒดํฌ์ธ ์ฒ๋ฆฌํ ๊ฒ์ผ๋ก ํ์ํ๋ค', () => {
checkInService.checkIn(attendee);
expect(attendee.isCheckedIn()).toBe(true);
});
it('์ฒดํฌ์ธ์ ๋ฑ๋กํ๋ค', () => {
checkInService.checkIn(attendee);
expect(checkInRecorder.recordCheckIn).toHaveBeenCalledWith(attendee);
});
// ํ
์คํธ ์ถ๊ฐ
it('์ฐธ๊ฐ์์ checkInNumber๋ฅผ ์ง์ ํ๋ค', () => {
checkInService.checkIn(attendee);
expect(attendee.getCheckInNumber()).toBe(checkInNumber);
});
});
});
});
์ ์์์ Promise
๊ฐ ์ด๋ฃจ์ด์ก๊ธฐ์ then
๋ฉ์๋์ ์ฒซ ๋ฒ์งธ ์ฝ๋ฐฑ์ด ํธ์ถ๋๊ณ , ์ด ์ฝ๋ฐฑ์ ํ๋ก๋ฏธ์ค๊ฐ ํ๊ณ ์๋ ์ฑ๊ณต์ ์ธ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ(checkInNumber
)๋ฅผ ๋๊ฒจ๋ฐ๋๋ค.
์กฐ๋ง๊ฐ ๋ฒ์ด์ง ์ผ๋ค์ ์ ๋ฆฌํด๋ณด์.
- ๋จ์ ํ
์คํธ๋
checkInService.checkIn
์ ํธ์ถํ๋ค. - ์ด ๋ฉ์๋๋
recorder.recordCheckIn
์ ํธ์ถํ๋ค. recordCheckIn
์ ๊ฐ์ ์ค์ธ ์คํ์ด๋recordCheckIn
์ดcheckInNumber
๊ฐ์ ์ง๋ ๊ท๊ฒฐ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ๋๋ก ์กฐ์ํ๋ค.- ์ด์ด์
recordCheckIn(attendee).then
์ ์ฑ๊ณต ์ฝ๋ฐฑ์ด ์คํ๋๋ค. - ์ฑ๊ณต ์ฝ๋ฐฑ
attendee.setCheckInNumber
๋checkInNumber
๋ฅผ ํผ๋ผ๋ฏธํฐ๋ก ๋ฐ๋๋ค. - ๊ฒฐ๊ตญ, ๋จ์ ํ ์คํธ ๋ง์ง๋ง ์ค์ ๊ธฐ๋์์ ๋ง์ ๋จ์ด์ง๋ค!
ํ์ง๋ง, ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ํ ์คํธ๋ ์คํจํ๋ค.
Promise
๋ ๋น๋๊ธฐ์ ์ด๋ค.- ์๋ฐ์คํฌ๋ฆฝํธ๋ ์ด๋ฒคํธ ๋ฃจํ๋ก ๋ฉํฐ ์ค๋ ๋ฉ์ ๋ชจ๋ฐฉํ์ง๋ง, ์ด๋๊น์ง๋ ์ฑ๊ธ์ค๋ ๋ ๋ฐฉ์์ผ๋ก ์์ง์ธ๋ค.
์ฆ, ์๋ฐ์คํฌ๋ฆฝํธ ์ด๋ฒคํธ ๋ฃจํ์์ ๋ค์ ์ฐจ๋ก๊ฐ ์ค๊ธฐ ์ ๊น์ง๋ Promise
์ then
๋ฉ์๋์ ๊ตฌํ๋ ์ฑ๊ณต ์ฝ๋ฐฑ์ผ๋ก ํ๋ก๊ทธ๋จ ์ ์ด๊ถ์ด ๋์ด๊ฐ ๋ฆฌ ์๋ค. ๋ค์ ๋งํด, ์ด๋ฏธ ๊ธฐ๋์ ํ๊ฐ๋ ์๋ ์ ๋๋ ํฐ๋ผ Promise
๊ท๊ฒฐ ์์ ์๋ ๋๋ฌด ๋ฆ์ด๋ฒ๋ฆฐ ๊ผด์ด๋ค.
์ฌ๋ฐ๋ฅด๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๋ ค๋ฉด ๋จ์ ํ
์คํธ๋ฅผ ์ด๋ป๊ฒ ๊ณ ์ณ์ผ ํ ๊น? ์ฒซ์งธ, checkInService.checkIn
์ด then
์ ํธ์ถํ์ฌ ์์ ํ ๊ฐ์ ๋ฐํํ๊ฒ ํ๋ค. ๊ท๊ฒฐ/์ฑ๊ณต ์ฝ๋ฐฑ์ผ๋ก ๋๋๋ฉด ๊ท๊ฒฐ Promise
๋ฅผ, ๋ฒ๋ฆผ/์คํจ ์ฝ๋ฐฑ์ ์ด๋ฅด๋ฉด ๋ฒ๋ฆผ Promise
๋ฅผ ๋ฐํํ ๊ฒ์ด๋ค.
var Conference = Conference || {};
Conference.checkInService = function(checkInRecorder) {
'use strict';
// ์ฃผ์
ํ ใ
heckInRecorder์ ์ฐธ์กฐ๊ฐ์ ๋ณด๊ดํ๋ค.
var recorder = checkInRecorder;
return {
checkIn: function(attendee) {
attendee.checkIn();
recorder.recordCheckIn(attendee).then(
function onRecordCheckInSucceeded(checkInNumber) {
attendee.setCheckInNumber(checkInNumber);
return Promise.resolve(checkInNumber);
},
function inRecordCheckInFailed(reason) {
attendee.undoCheckIn();
return Promise.reject(reason);
}
);
}
};
};
๋์งธ, then
์ด ๋ด์ด์ค Promise
๊ฐ ํด๊ฒฐ๋๊ธฐ ์ ์ ๋จ์ ํ
์คํธ๊ฐ ์์ ์ ๊ธฐ๋์์ ํ๊ฐํ์ง ๋ชปํ๊ฒ ๋ง์์ผ ํ๋ค. ๊ธฐ๋์์ then
๋ด๋ถ์์ ์คํ์ํค๋ฉด ๋๋ค.
it('์ฐธ๊ฐ์์ ์ฒดํฌ์ธ ๋ฒํธ๋ฅผ ์ธํ
ํ๋ค', (done) => {
checkInService.checkIn(attendee).then(
function onPromiseResolved() {
expect(attendee.getCheckInNumber()).toBe(checkInNumber);
done();
},
function onPromiseRejected() {
expect('์ด ์คํจ ๋ถ๊ธฐ ์ฝ๋๊ฐ ์คํ๋๋ค').toBe(false);
done(); // ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ๋ค ๋๋๋ฉด ๋ฐ๋์ ์ด ํจ์๋ฅผ ํธ์ถํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ํ์์์ ์๋ฌ
},
);
});
๋น๋๊ธฐ ์ฝ๋๋ฅผ ํ ์คํธํ ๋๋ ํญ์ ์ฌ์ค๋ฏผ์
done()
์ ์จ๋ผ.
๋ค์์ ์คํจํ๋ ๋ถ๊ธฐ ๋ก์ง์ ํ์ธํ๋ ํ ์คํธ๋ค.
describe('checkInRecorder ์คํจ ์', () => {
var recorderError = '์ฒดํฌ์ธ ๋ฑ๋ก ์คํจ!';
beforeEach(() => {
spyOn(checkInRecorder, 'recordCheckIn').and.returnValue(
Promise.reject(new Error(recorderError)),
);
spyOn(attendee, 'undoCheckIn');
});
it('๊ธฐ๋ ์ฌ์ ์ ํจ๊ป ๋ฒ๋ฆผ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ๋ค.', () => {
checkInService.checkIn(attendee).then(
function promiseResolved() {
expect('์ด ์ฑ๊ณต ํจ์๊ฐ ์คํ๋๋ค.').toBe(false);
done();
},
function promiseRejected(reason) {
expect(reason.message).toBe(recorderError);
done();
},
);
});
});
๐ ํ๋ก๋ฏธ์ค ์์ฑ๊ณผ ๋ฐํโ
์นํ์ checkInRecorder
๋ฅผ ๊ตฌํํ๊ณ ์ ํ๋ค. ๊ทธ๋ ํ์ฌ ์ง์์ ๋ฐํ์ผ๋ก ๋จ์ ํ
์คํธ๋ฅผ ๊ตฌ์ํ๋ค.
describe('Conference.checkInRecorder', () => {
'use strict';
var attendee, checkInRecorder;
beforeEach(() => {
attendee = Conference.attendee('Tom', 'Jones');
checkInRecorder = Conference.checkInRecorder();
});
describe('recordCheckIn(attendee)', () => {
it('์ฐธ๊ฐ์๊ฐ ์ฒดํฌ์ธ๋๋ฉด checkInNumber๋ก ๊ท๊ฒฐ๋ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ๋ค', (done) => {
attendee.checkIn();
checkInRecorder.recordCheckIn(attendee).then(
function promiseResolved(actualCheckInNumber) {
expect(typeof actualCheckInNumber).toBe('number');
done();
},
function promiseRejected() {
expect('ํ๋ก๋ฏธ์ค๋ ๋ฒ๋ ค์ก๋ค').toBe(false);
done();
},
);
});
it('์ฐธ๊ฐ์๊ฐ ์ฒดํฌ์ธ๋์ง ์์ผ๋ฉด ์๋ฌ์ ๋ฒ๋ฆผ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ๋ค', (done) => {
checkInRecorder.recordCheckIn(attendee).then(
function promiseResolved() {
expect('ํ๋ผ๋ฏธ์ค๋ ๊ท๊ฒฐ๋๋ค').toBe(false);
done();
},
function promiseRejected(reason) {
expect(reason instanceof Error).toBe(true);
expect(reason.message)
.toBe(checkInRecorder.getMessages().mustBeCheckedIn)
done();
},
);
});
});
});
์ด์ ํ
์คํธ์ ์ฑ๊ณตํ๋๋ก checkInRecorder
๋ฅผ ์์ฑํ๋ค.
var Conference = Conference || {};
Conference.checkInRecorder = function() {
'use strict';
var messages = {
mustBeCheckedIn: '์ฐธ๊ฐ์๋ ์ฒดํฌ์ธ๋ ๊ฒ์ผ๋ก ํ์๋์ด์ผ ํ๋ค.',
};
return {
getMessages: function() {
return messages;
},
recordCheckIn: function(attendee) {
return new Promise(function(resolve, reject) {
if (attendee.isCheckedIn()) {
resolve(4444); // ์ผ๋จ ์๋ฌด ์ซ์๋ ๋ฃ๋๋ค.
} else {
reject(new Error(messages.mustBeCheckedIn));
}
});
},
};
};
์นํ์ ์ ์ ๊ณ ๊ฐ๋ฅผ ๊ฐธ์ฐ๋ฑํ๋๋ ์ฝ๋ฐฑ์์ Promise.resolve
์ Promise.reject
๋ฅผ ๋ฐํํ์ง ๋ง๊ณ ์์ ์ฒ์๋ถํฐ checkInService.checkIn
์์ ์ง์ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ง๋ค์ด๋ ๋์ง ์๋ ์๊ฐํ๋ค.
var Conference = Conference || {};
Conference.checkInService = function(checkInRecorder) {
'use strict';
// ์ฃผ์
ํ ใ
heckInRecorder์ ์ฐธ์กฐ๊ฐ์ ๋ณด๊ดํ๋ค.
var recorder = checkInRecorder;
return {
checkIn: function(attendee) {
return new Promise(function checkInPromise(resolve, reject) {
attendee.checkIn();
recorder.recordCheckIn(attendee).then(
function onRecordCheckInSucceeded(checkInNumber) {
attendee.setCheckInNumber(checkInNumber);
resolve(checkInNumber);
},
function inRecordCheckInFailed(reason) {
attendee.undoCheckIn();
reject(reason);
}
);
});
}
};
};
๐ XMLHttpRequest ํ ์คํ โ
์ด์ recordCheckIn
์ XMLHttpRequest
๋ฅผ ์์ฑํ๋ค.
์ฌ์ค๋ฏผ์์ XMLHttpRequest
๋ฅผ ํ
์คํธํ ๋ jasmine-ajax๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ
์คํธ๋ฅผ ์์ฑํ ์ ์๋ค.
describe('Conference.checkInRecorder', () => {
'use strict';
var attendee, checkInRecorder;
beforeEach(() => {
attendee = Conference.attendee('์ผ์
', '์ด');
attendee.setId(777);
checkInRecorder = Conference.checkInRecorder();
// *** 1 ***
// ์ฌ์ค๋ฏผ XMLHttpRequest ๋ชจ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
jasmine.Ajax.install();
});
afterEach(() => {
// ๋ค ๋๋ ํ์๋ ์๋ XMLHttpRequest๋ก ๋๋ ค๋๋๋ค.
jasmine.Ajax.uninstall();
});
describe('recordCheckIn(attendee)', () => {
// *** 9 ***
it('HTTP ์์ฒญ์ด ์ฑ๊ณตํ์ฌ ์ฐธ๊ฐ์๊ฐ ์ฒดํฌ์ธ๋๋ฉด checkInNumber๋ก ๊ท๊ฒฐ๋ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ๋ค', () => {
var expectedCheckInNumber = 1234;
var request;
attendee.checkIn();
// *** 2 ***
checkInRecorder.recordCheckIn(attendee).then(
function promiseResolved(actualCheckInNumber) {
// *** 8 ***
expect(actualCheckInNumber).toBe(expectedCheckInNumber);
},
function promiseRejected() {
expect('ํ๋ก๋ฏธ์ค๋ ๋ฒ๋ ค์ก๋ค').toBe(false);
},
);
// *** 4 ***
request = jasmine.Ajax.requests.mostRecent();
// *** 5 ***
expect(request.url).toBe('/checkin/' + attendee.getId());
// *** 6 ***
request.response({
'status': 200,
'contextType': 'text/plain',
'responseText': expectedCheckInNumber,
});
});
it('HTTP ์์ฒญ์ด ์คํจํ์ฌ ์ฐธ๊ฐ์๊ฐ ์ฒดํฌ์ธ๋์ง ์์ผ๋ฉด ์ ํํ ๋ฉ์์ง์ ํจ๊ป ๋ฒ๋ ค์ง ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ๋ค', () => {
var request;
attendee.checkIn();
checkInRecorder.recordCheckIn(attendee).then(
function promiseResolved(actualCheckInNumber) {
expect('ํ๋ก๋ฏธ์ค๋ ๊ท๊ฒฐ๋๋ค').toBe(false);
},
function promiseRejected(reason) {
expect(reason instanceof Error).toBe(true);
expect(reason.message)
.toBe(checkInRecorder.getMessages().httpFailure);
}
);
request = jasmine.Ajax.requests.mostRecent();
expect(request.url).toBe('/checkin/' + attendee.getId());
request.response({
'status': 404,
'contentType': 'text/plain',
'responseText': '์ด๋์ ์๋ฌ๊ฐ ๋ฌ์ต๋๋ค.',
});
});
it('์ฐธ๊ฐ์๊ฐ ์ฒดํฌ์ธ๋์ง ์์ผ๋ฉด ์๋ฌ์ ๋ฒ๋ฆผ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ๋ค', (done) => {
checkInRecorder.recordCheckIn(attendee).then(
function promiseResolved() {
expect('ํ๋ก๋ฏธ์ค๋ ๊ท๊ฒฐ๋๋ค').toBe(false);
done();
},
function promiseRejected(reason) {
expect(reason instanceof Error).toBe(true);
expect(reason.message)
.toBe(checkInRecorder.getMessages().mustBeCheckedIn);
done();
},
);
});
});
});
๋น์ฅ ํ
์คํธํ๋ฉด ์ ๋ถ ์คํจํ ํ
๋ XMLHttpRequest
๋ฅผ checkInRecorder
์ ์จ๋ฃ๋๋ค.
var Conference = Conference || {};
Conference.checkInRecorder = function() {
'use strict';
var messages = {
mustBeCheckedIn: '์ฐธ๊ฐ์๋ ์ฒดํฌ์ธ๋ ๊ฒ์ผ๋ก ํ์๋์ด์ผ ํ๋ค.',
httpFailure: 'HTTP ์์ฒญ ์คํจ!',
};
return {
getMessages: function() {
return messages;
},
recordCheckIn: function(attendee) {
return new Promise(function(resolve, reject) {
if (attendee.isCheckedIn()) {
// *** 3 ***
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function onreadystatechange() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
// *** 7 ***
resolve(xhr.responseText);
} else {
reject(new Error(messages.httpFailure));
}
}
};
xhr.open('POST', '/checkin/' + attendee.getId(), true);
xhr.send();
} else {
reject(new Error(messages.mustBeCheckedIn));
}
});
},
};
};
๐ ํ๋ผ๋ฏธ์ค ์ฒด์ด๋โ
์ฌ๋ฟ: ์ด๋ ๊ฒ ์ฝ๋ฉํ๋ฉด ์ค์ค์ด ์ฒด์ด๋ํ ์ ์๊ฒ ๋๋ฐ?
then
์ด ๊ท๊ฒฐ ์ฝ๋ฐฑ ๋ง๋ค ์๊ธฐ ์์ ์๋then
์ด ์ฑ๊ณตํ ๋๋ง ์คํ๋๊ฒ ํ๋ฉด ๋์์?
์นํ: ๋ฌผ๋ก ๊ทธ๋ ๊ฒ ํ ์ ์์ง๋ง, ๊ทธ๋ฌ๋ฉด ๋จ๊ณ๋ง๋ค ๋ ๋ฒ์งธ(๋ฒ๋ฆผ) ์ฝ๋ฐฑ์ด ํ์ํ์ง ์์๊น? ๊ฒ๋ค๊ฐXMLHttpRequest
๊ฐ์ฒด๋ฅผ ์ฌ๋ฟ ์ค์ ํด์ ๋จ์ ํ ์คํธ๋ฅผ ํด์ผ ํ ์ง๋ ๋ชฐ๋ผ.
์ฌ๋ฟ: ๋ง์ ๊ทธ๋ฌ๋ค. ๊ทผ๋ฐ ๋ง์ด์ผ, ๋ง์ผ ํ ๋จ๊ณ๋ผ๋return
์ด ๋น ์ง๋ฉด, ๋ค์ ๋จ๊ณ์์undefined
๊ฐ ๋์ด์ค๊ฒ ์ง? ์ด๋ฐ ์ค์๊ฐ ์ ๋ฒ ์์ฃผ ์ผ์ด๋ ๊ฒ ๊ฐ์๋ฐ?
์นํ: ์ ๊ทธ๋์ ํ ์คํธํ ๋ ์ค์ checkInNumber
๊ฐ ์ฌ๋ฐ๋ฅธ์ง ํ์ธํ๋ ๊ฑฐ์์?
์ฌ๋ฟ: ๊ธ์, ๊ทธ๋ ๊ฒ ํ๋ค๊ณ ์ ๋๋ก ์ฒ๋ฆฌ๋ ๊ฒ ๊ฐ์ง ์์๋ฐ? ์๋ฅผ ๋ค์ด, ๋ง์ ํ๋jasmine.Ajax
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ ์ํฉ์ด๋ฉด ์ด์ฐ ๋๊ฒ ์ด? ๊ทธ๋์ ๋ง์ธ๋ฐ,Promise
์ ๋ฒ์ฉ์ ์ผ๋ก ์ธ ๋งํ ๋ชจ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ์ ๊ฑด ์์๊น?
- ์ฌ๋ฟ์ ์ ๋ต์ ์ฐพ์๋ค.
๐ ํ๋ผ๋ฏธ์ค ๋ํผโ
์ฌ๋ฟ: ๋ค๊ฐ ์ง ์ฝ๋๋ ๋จ์ ๋ฌด์ํ์ง๋ง
Promise
๋ฅผ ๊ท๊ฒฐ์ํฌ ๋ ๋ฌธ์ ๊ฐ ๋ ๊ฑฐ์ผ. ์ด๋ฏธ ๊ท๊ฒฐ๋ ์ํ์์Promise
๋ฅผ ๋ง๋๋ ๊ฑธ ๋งํ๋ ๊ฒ ์๋๊ณ , ์ด๋ฏธ ๊ทธ๊ฑด ๋ค๊ฐ ํ ์ผ์ด๋๊น, ์ด๋ฏธ ์๋Promise
์ ๊ท๊ฒฐ/๋ฒ๋ฆผ ๋ง์ด์ผ.
์นํ: ๊ทธ๊ฒ๊น์ง ๋ชฐ๋๋ค. ๊ทธ๋ฐ๋ฐ ์ง๊ธ ๋ณด๋Promise
ํ๋กํ ํ์ ์then
๊ณผcatch
๋ ๋ฉ์๋๊ฐ ์๋๋ฐ?
์ฌ๋ฟ: ๋ฐ๋ก ๊ทธ๊ฑฐ์ผ. ํ์ง๋ง ๋ฒ์จ ๋๋ํ ์ฌ๋๋ค์ด ์ ์ฌPromise
๊ฐ์ฒด๋ฅผ ์์กด์ฑ์ผ๋ก ์ฃผ์ ํ๋,Deferred
๊ฐ์ ๋ํผ๋ฅผ ๋ง๋ค์ด๋จ๋๋ผ๊ณ . ์ด๊ฑธ ๋จ์ ํ ์คํธํ ๋ ์ง์ง ํ๋ผ๋ฏธ์ค๋ ๊ฐ์ง ํ๋ผ๋ฏธ์ค์ฒ๋ผ ํ์ฉํ ์ ์์ ๊ฑฐ ๊ฐ์.
// ์ต๊ทค๋ฌ 1.3์์ Q๋ผ๋ ํ๋ผ๋ฏธ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ
var deferred = $q.defer(); // ๋ฏธ๋ค์ง ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
var promise = deferred.promise; // promise๋ผ๋ ํ๋กํผํฐ๊ฐ ์๋ค.
deferred.resolve(1234); // 1234 ๊ฐ์ผ๋ก ํ๋ผ๋ฏธ์ค๋ฅผ ๊ท๊ฒฐํ๋ค.
๐ ์ํ์ ์๋ช โ
์ฌ๋ฟ:
Promise
๋ฅผ ๋ค๋ฃฐ ๋ ๋ง์ด์ผ. ์ง์ง๋Deferred
์ด ๊ฐ์ง๋Promise
์ ๊ท๊ฒฐ๊ณผ ์ด๋ฃธ ์ฌ์ด์ ๋ฏธ๋ฌํ ์ฐจ์ด๋ฅผ ์ดํดํด์ผ ํด. ์ด๋ฃธPromise
๋ฅผ ์์ฑํ๋ ํจ์๋ฅผPromise.fulfill
์ด ์๋๋ผPromise.resolve
๋ผ๊ณ ๋ถ๋ฅธ๋จ ๋ง์ด์ง.Promise
๋ ๊ผญ ์ด๋ค ๊ฐ์ผ๋ก ์ด๋ฃจ์ด์ ๊ท๊ฒฐ์์ผ์ผ ํ๋จ ๋ฒ์ด ์๊ธฐ ๋๋ฌธ์ด์ผ. ๋ค๋ฅธPromise
๋ก๋ ์ผ๋ง๋ ์ง ๊ท๊ฒฐ์ํฌ ์ ์์ด. ์ด๋ฏธ ๋ฒ๋ ค์งPromise
๋ ๋์ค์ ๋ฒ๋ ค์งPromise
๋ผ๋ ์๊ด์์ด. ๊ท๊ฒฐ๋์๋ค๋ ๋ง์ ํ๋ผ๋ฏธ์ค ์๋ช ์ด ์ด๋ ํ์ชฝ์ผ๋ก ๊ฒฐ์ ๋๋จ ๋ป์ด๊ฑฐ๋ . ํ๋์ ๊ฐ์ผ๋ก ๋ชป ๋ฐํ๋ ์ง, ์๋๋ฉด ๋ค๋ฅธ ํ๋ผ๋ฏธ์ค์ ๊ถ๊ทน์ ์ธ ์๋ช ์ด ๋๋ ๊ฒ์ง.
๊นํ๋ธ๋ฅผ ๋ค์ ๋ณด๋ ์ํ์ ์ด๋ช ์ด๋ผ๋ ์ ๋ชฉ์ผ๋ก ์ ๋ฆฌ๊ฐ ์ ๋์ด์๋ ์ฌ์ดํธ๊ฐ ์๋๋ผ. (์ฐธ๊ณ )
๊ธฐ๋ณธ์ ์ผ๋กPromise
๋ ์ธ์ ๋ ์ธ ๊ฐ์ง ์ํ(state), ์ฆ ์ด๋ฃธ(fulfilled), ๋ฒ๋ฆผ(rejected), ๋ณด๋ฅ(pending) ์ค ํ๋์ผ. ๊ธฐ์ ์ ์ผ๋ก ๊น๊ฒ ๋ค์ด๊ฐ๋ฉด ๋์ฑ ๋ฏธ์ธํ ์ฐจ์ด์ ์ด ์์ง๋ง, ๋์ฒด๋ก ์ฐ๋ฆฌ๊ฐ ์ง์ํ๋ ๊ทธ๋๋ก์ผ.
์๋ช (fate)์ ๊ท๊ฒฐ(resolved)๊ณผ ๋ฏธ๊ฒฐ(unresolved), ๋ ๊ฐ์ง์ผ. ๋ฏธ๊ฒฐ ํ๋ผ๋ฏธ์ค์ ์ํ๋ ํญ์ ๋ณด๋ฅ์ง๋ง, ๊ท๊ฒฐ ํ๋ผ๋ฏธ์ค๋ ์ธ ๊ฐ์ง ์ํ ์ค ํ๋๊ฐ ๋ ์ ์์ง. ๋ฌผ๋ก ์ด๋ฃธ ์ํ๊ฐ ์ ์ผ ์ผ๋ฐ์ ์ด์ง๋ง.
then
์์ ๋ฒ๋ฆผ ์ฒ๋ฆฌํPromise
๋ฅผ ๋ฐํํด๋ ๋จ์ ํ ์คํธ์์๋ ๊ท๊ฒฐ ๋ถ๋ถ์ผ๋ก ํ๋ฌ๊ฐ ์ ์๋ค๋ ์ฌ์ค์ด ์ฐ๋ฆฌ ์ง๊ด์ ๋ค์ ๋ฐํ๋ ๊ฒ ๊ฐ์ง๋ง, ์ด ๋ฒ๋ฆผ ์ฝ๋ฐฑ์ด ๊ท๊ฒฐ ํ๋ผ๋ฏธ์ค๋ (๋ค์์ ๊ท๊ฒฐ ํ๋ฏธ์ค๋ก ๋ฐ๋) ๋น ๊ฐ์ ๋ฐํํ๋ ์ผ์ ๊ฐ๋ฅํ๊ฒ ์ง.