javascript promises
TRANSCRIPT
JAVASCRIPT PROMISES in
ECMAScript6 (Harmony)
01 02 03 04
Promise란 무엇인가?
Promise 사용하기
Promise의 특징
Promise 직접 구현하기
전통적인 콜백 패
턴이 가지고 있는
문제와 Promise 정
의및 사용 방법에
대해서 개괄적으로
살펴본다.
Promise의 정적 메
서드와 인스턴스
메서드 , 그리고
thenable에 관한
개념 등 조금 더 다
양하고 자세한 내
용을 살펴본다.
Promise에 대해
잘 알려져 있지 않
는 중요한 특징 몇
가지를 소개한다.
ES6����������� ������������������ Promises의����������� ������������������ ����������� ������������������
베이스가����������� ������������������ 되는����������� ������������������ ����������� ������������������
Promise/A+의����������� ������������������ 사����������� ������������������
양을����������� ������������������ 직접����������� ������������������ 구현해����������� ������������������
봄 으 로 써����������� ������������������ ����������� ������������������
Promise에����������� ������������������ 대한����������� ������������������ ����������� ������������������
이해를����������� ������������������ 더욱����������� ������������������ 높인����������� ������������������
다.����������� ������������������
2
전통적인 콜백 패턴의 문제 1
여러운 비동기 예외 처리
3
try{ setTimeout(function(){ throw new Error('에러가 발생했다.'); }, 1000); }catch(err){ console.error(err); console.log('에러를 복구했다.'); }
전통적인 콜백 패턴의 문제 1
여러운 비동기 예외 처리
try{ setTimeout(function(){ throw new Error('에러가 발생했다.'); }, 1000); }catch(err){ console.error(err); console.log('에러를 복구했다.'); }
global
4
전통적인 콜백 패턴의 문제 1
여러운 비동기 예외 처리
try{ setTimeout(function(){ throw new Error('에러가 발생했다.'); }, 1000); }catch(err){ console.error(err); console.log('에러를 복구했다.'); }
global setTimeout() handler 호출
콜백 등록
5
전통적인 콜백 패턴의 문제 1
여러운 비동기 예외 처리
try{ setTimeout(function(){ throw new Error('에러가 발생했다.'); }, 1000); }catch(err){ console.error(err); console.log('에러를 복구했다.'); }
global time event setTimeout() handler 호출
콜백 등록 발화
6
전통적인 콜백 패턴의 문제 1
여러운 비동기 예외 처리
try{ setTimeout(function(){ throw new Error('에러가 발생했다.'); }, 1000); }catch(err){ console.error(err); console.log('에러를 복구했다.'); }
global time event setTimeout() handler 호출
콜백 등록 발화
예외
7
전통적인 콜백 패턴의 문제 1
여러운 비동기 예외 처리
try{ setTimeout(function(){ throw new Error('에러가 발생했다.'); }, 1000); }catch(err){ console.error(err); console.log('에러를 복구했다.'); }
global time event setTimeout() handler 호출
콜백 등록 발화
예외 통지 예외
8
전통적인 콜백 패턴의 문제 2
복수의 비동기 처리
fs.readdir(source, function(err, files){ if(err){ console.log('Error finding files : ' + err); }else{ file.forEach(function(filename, fileIndex){ console.log(filename); gm(source + filename).size(function(err, vlaues){ if(err){ console.log('Error identifying file size : ' + err); }else{ console.log(filename + ' : ' + values); aspect = (values.width / value.height); widths.forEach(function(width, wwidthIndex){ height = Math.round(width /aspect); console.log('resizing ' + filename + 'to ' + height + 'x' + height); this.resize(width, height).write(
destination + 'w' + width + '_' + filename, function(err){ if(err){ console.log('Error writing file : ' + err); } } ); }); } }); }); } })
9
Promise란?
정의
Promise란 비동기 처리 로직을 추상화한 객체와 그것을 조작하는 방식을 말한다.
E 언어에서 처음 고안됐으며 병렬 및 병행 프로그래밍을 위한 일종의 디자인이다.
비동기����������� ������������������ 로직����������� ������������������
전달
<Promise>
인터페이스����������� ������������������
의존 구현
<액터>
10
Promise란?
효과
전통적인 콜백 패턴이 가진 단점을 일부 보완한다.
비동기 처리 시점을 명확하게 표현한다.
Promise 객체의 인터페이스를 이용해 다양한 비동기 처리를 패턴화할 수 있다.
복잡하고 불편한 비동기 예외 처리를 손쉽게 다룰 수 있다.
11
Promise란?
명세
초기 작업
ES6 DRAFT
Promises/A+
https://github.com/domenic/promises-unwrapping
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-constructor
Promises/A+����������� ������������������ :����������� ������������������ https://promisesaplus.com/����������� ������������������
12
Promise란?
사용된 곳
if('serviceWorker' in navigator){ navigator.serviceWorker.register('/sw=text/sw.js', { scope: '/' }).then(function(sw){ // registration worked console.log('Registration succeeded.'); }).catch(function(err){ // registration filed console.log('Registration filed with ' + err); }) }
function writeArrayToStream(array, writableStream){ array.forEach(chunk = > writableStream.write(chunk)); return writableStream.close(); } writeArrayToStream([1, 2, 3, 4, 5], writableStream) .then(() => console.log('All done!')) .catch(e => console.log('Error with the stream : ' + e));
Service Worker API
Streams API
13
Promise 살펴보기
Promises API
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
strawman(폐기)����������� ������������������ :����������� ������������������ http://wiki.ecmascript.org/doku.php?id=strawman:promises����������� ������������������
Constructor
var promise = new Promise(function(resolve, reject){ // 비동기 처리 작성 // 처리가 끝나면 resolve 또는 reject 호출 });
Instace Method Static Method
Promise.prototype.then(onFulfilled,����������� ������������������ onRejected)����������� ������������������
Promise.prototype.catch(onRejected)����������� ������������������
Promise.all()����������� ������������������
Promise.race()����������� ������������������
Promise.resolve()����������� ������������������
Promise.reject()����������� ������������������
14
Promise 살펴보기
워크플로우
/** * @returns {Promise} */ function asyncFunction(){ return new Promise(function(resolve, reject){ setTimeout(function(){ resolve('Async Hello world!!'); }, 16); }) }
asyncFunction().then(function(value){ console.log(value); }).catch(function(error){ console.log(error); });
asyncFunction().then(function(value){ console.log(value); }, function(error){ console.log(error); });
asyncFunction()은 Promise의 인스턴스를 반환할 뿐이며 비동기 로직은 모두 Promise에 추상화된다. 비동기 처리가 성공했을 때 호출될 콜백은 then(), 실패했을 때 호출될 콜백은 catch()로 등록한다. catch()는 then()을 이용해 대체할 수도 있다.
15
Promise 살펴보기
상태
초기 상태
성공(또는 해결) 상태
실패(또는 거부) 상태
불편 상태
unresolved����������� ������������������ 또는����������� ������������������ Pending,����������� ������������������ ����������� ������������������
성공도����������� ������������������ 실패도����������� ������������������ 아닌����������� ������������������ 초기����������� ������������������ 상태����������� ������������������
has-resolution����������� ������������������ 또는����������� ������������������ Fulfilled,����������� ������������������ ����������� ������������������
성공(resolve)했을����������� ������������������ 때의����������� ������������������ 상태����������� ������������������
has-rejection����������� ������������������ 또는����������� ������������������ Rejected,����������� ������������������ ����������� ������������������
실패(reject)했을����������� ������������������ 때의����������� ������������������ 상태����������� ������������������
Settled,����������� ������������������ 성공����������� ������������������ 또는����������� ������������������ 실패����������� ������������������ 했을����������� ������������������ 때의����������� ������������������ 상태.����������� ������������������
Fulfilled
Rejected
Pending
16
Promise 맛보기
객체 생성
1. new Promise(fn)으로 promise 객체를 생성한다. 2. fn에는 비동기 처리를 작성한다.
• 처리 결과가 정상이라면 resolve(결과 값)을 호출한다. • 처리 결과가 비정상이라면 reject(error)을 호출한다.
function getJSON(URL){ return new Promise(function(resolve, reject){ var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function(){ if(req.status === 200){ resolve(JSON.parse(req.responseText)); }else{ reject(new Error(req.statusText)); } }; req.onerror = function(){ reject(new Error(req.statusText)); }; req.send(); }) }
function doSomething(callback){ var value = 42; if(value === 42){ callback(null, value); }else{ callback(new Error('에러'), null); } }
17
Promise 맛보기
객체 사용
Promise의����������� ������������������ 인스턴스����������� ������������������ 메서드를����������� ������������������ 이용해����������� ������������������ 객체의����������� ������������������ 상태가����������� ������������������ ����������� ������������������ 변화할����������� ������������������ 때����������� ������������������ 한����������� ������������������ 번만����������� ������������������ 호출될����������� ������������������ 함수를����������� ������������������ 등록한다.����������� ������������������
Pending
18
Promise 맛보기
객체 사용
Promise의����������� ������������������ 인스턴스����������� ������������������ 메서드를����������� ������������������ 이용해����������� ������������������ 객체의����������� ������������������ 상태가����������� ������������������ ����������� ������������������ 변화할����������� ������������������ 때����������� ������������������ 한����������� ������������������ 번만����������� ������������������ 호출될����������� ������������������ 함수를����������� ������������������ 등록한다.����������� ������������������
resolve()가����������� ������������������ 호출����������� ������������������ 됐을때,����������� ������������������ 객체����������� ������������������ 상태가����������� ������������������ Fulfilled����������� ������������������ 됐음을����������� ������������������ 뜻하며����������� ������������������ onFulfilled가����������� ������������������ 호출된다.
onFulfilled
resolve() value
Pending
19
Promise 맛보기
객체 사용
Promise의����������� ������������������ 인스턴스����������� ������������������ 메서드를����������� ������������������ 이용해����������� ������������������ 객체의����������� ������������������ 상태가����������� ������������������ ����������� ������������������ 변화할����������� ������������������ 때����������� ������������������ 한����������� ������������������ 번만����������� ������������������ 호출될����������� ������������������ 함수를����������� ������������������ 등록한다.����������� ������������������
resolve()가����������� ������������������ 호출����������� ������������������ 됐을때,����������� ������������������ 객체����������� ������������������ 상태가����������� ������������������ Fulfilled����������� ������������������ 됐음을����������� ������������������ 뜻하며����������� ������������������ onFulfilled가����������� ������������������ 호출된다.
reject()가����������� ������������������ 호출����������� ������������������ 됐을때,����������� ������������������ 객체����������� ������������������ 상태가����������� ������������������ Rejected����������� ������������������ 됐음을����������� ������������������ 뜻하며����������� ������������������ onRejected가����������� ������������������ 호출된다.
onRejected
reject() error
Pending
20
Promise 맛보기
객체 사용
Promise의����������� ������������������ 인스턴스����������� ������������������ 메서드를����������� ������������������ 이용해����������� ������������������ 객체의����������� ������������������ 상태가����������� ������������������ ����������� ������������������ 변화할����������� ������������������ 때����������� ������������������ 한����������� ������������������ 번만����������� ������������������ 호출될����������� ������������������ 함수를����������� ������������������ 등록한다.����������� ������������������
resolve()가����������� ������������������ 호출����������� ������������������ 됐을때,����������� ������������������ 객체����������� ������������������ 상태가����������� ������������������ Fulfilled����������� ������������������ 됐음을����������� ������������������ 뜻하며����������� ������������������ onFulfilled가����������� ������������������ 호출된다.
reject()가����������� ������������������ 호출����������� ������������������ 됐을때,����������� ������������������ 객체����������� ������������������ 상태가����������� ������������������ Rejected����������� ������������������ 됐음을����������� ������������������ 뜻하며����������� ������������������ onRejected가����������� ������������������ 호출된다.
onRejected
reject() error
onFulfilled
resolve() value
getJSON('/api/stores').then(function(value){ console.log(value); }).catch(function(error){ console.log(error.message); });
getJSON(’/api/stores').then(function(value){ console.log(value); }, function(error){ console.log(error.message); });
Pending
21
PROMISES 사용하기
Promise.resolve
new Promise() 단축 표기
Promise.resolve()를����������� ������������������ 사용하면����������� ������������������ new����������� ������������������ Promise()����������� ������������������ 구문을����������� ������������������ 단축해����������� ������������������ 표기할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������
23
Promise.resolve
new Promise() 단축 표기
Promise.resolve()를����������� ������������������ 사용하면����������� ������������������ new����������� ������������������ Promise()����������� ������������������ 구문을����������� ������������������ 단축해����������� ������������������ 표기할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������
var promise = new Promise(function(resolve){ resolve(42); }).then(function(value){ console.log(value); });
var promise = Promise.resolve(42).then(function(value){ console.log(value); });
24
Promise.resolve
thenable과 resolve
then()을����������� ������������������ 가진����������� ������������������ 유사����������� ������������������ promise����������� ������������������ 객체를����������� ������������������ thenable한����������� ������������������ 객체라고����������� ������������������ 한다.����������� ������������������ Promise.resolve()는����������� ������������������ thenable����������� ������������������ 객체를����������� ������������������ promise����������� ������������������ 객체로����������� ������������������ 변환할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������ (이����������� ������������������ 기능은����������� ������������������ 과거����������� ������������������ Promise.cast()라는����������� ������������������ 별도의����������� ������������������ 메서드로����������� ������������������ 존재했었다.)����������� ������������������
25
Promise.resolve
thenable과 resolve
then()을����������� ������������������ 가진����������� ������������������ 유사����������� ������������������ promise����������� ������������������ 객체를����������� ������������������ thenable한����������� ������������������ 객체라고����������� ������������������ 한다.����������� ������������������ Promise.resolve()는����������� ������������������ thenable����������� ������������������ 객체를����������� ������������������ promise����������� ������������������ 객체로����������� ������������������ 변환하는����������� ������������������ 기능이����������� ������������������ 있다.����������� ������������������ (이����������� ������������������ 기능은����������� ������������������ 과거����������� ������������������ Promise.cast()라는����������� ������������������ 별도의����������� ������������������ 메서드로����������� ������������������ 존재했었다.)����������� ������������������
26
var promise = Promise.resolve($.ajax('/api/comments')); promise.then(function(value){ console.log(value); }).catch(function(error){ console.log(error.statusText); });
노트����������� ������������������ :����������� ������������������ jQuery.ajax()가����������� ������������������ 반환하는����������� ������������������ jqXHR����������� ������������������ 객체는����������� ������������������ Deferred����������� ������������������ Object를����������� ������������������ 상속한다.����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 하지만����������� ������������������ Deferred는����������� ������������������ Promise/A+나����������� ������������������ ES6����������� ������������������ Promise����������� ������������������ 사양을����������� ������������������ 따른����������� ������������������ 것이����������� ������������������ 아니므로����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 특정����������� ������������������ 처리시����������� ������������������ 문제가����������� ������������������ 발생할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������
Promise.reject
new Promise() 단축 표기
Promise.reject()를����������� ������������������ 사용하면����������� ������������������ new����������� ������������������ Promise()����������� ������������������ 구문을����������� ������������������ 단축해����������� ������������������ 표기할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������
27
var promise = new Promise(function(resolve, reject){ reject(new Error('오류')); }).catch(function(error){ console.log(error.message); });
Promise.reject(new Error('오류')).catch(function(error){ console.log(error.message); });
Promise.prototype.then
메서드 체인
promise����������� ������������������ 객체의����������� ������������������ then()과����������� ������������������ catch()를����������� ������������������ 이용해����������� ������������������ 메서드를����������� ������������������ 체인할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������ 메서드를����������� ������������������ 체인하여����������� ������������������ 작성한����������� ������������������ 콜백����������� ������������������ 함수는����������� ������������������ 등록한����������� ������������������ 순서대로����������� ������������������ 처리된다.����������� ������������������
28
Promise.prototype.then
메서드 체인
promise����������� ������������������ 객체의����������� ������������������ then()과����������� ������������������ catch()를����������� ������������������ 이용해����������� ������������������ 메서드를����������� ������������������ 체인할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������ 메서드를����������� ������������������ 체인하여����������� ������������������ 작성한����������� ������������������ 콜백����������� ������������������ 함수는����������� ������������������ 등록한����������� ������������������ 순서대로����������� ������������������ 처리된다.����������� ������������������
29
function taskA(){ console.log('Task A'); } function taskB(){ console.log('Task B'); } function onRejected(error){ console.log('Catch Error: A or B', error); } function finalTask(){ console.log('Final Task'); } var promise = Promise.resolve(); promise.then(taskA) .then(taskB) .catch(onRejected) .then(finalTask);
TaskA
TaskB
FinalTask
onRejected
Promise.prototype.then
메서드 체인
만약����������� ������������������ TaskA에서����������� ������������������ 에러가����������� ������������������ 발생하면����������� ������������������ TaskB는����������� ������������������ 실행되지����������� ������������������ ����������� ������������������ 않고����������� ������������������ ����������� ������������������ onRejected와����������� ������������������ finalTask����������� ������������������ 순으로����������� ������������������ 처리된다.����������� ������������������
30
function taskA(){ console.log('Task A'); throw new Error('throw Error @ Task A'); } function taskB(){ console.log('Task B'); } function onRejected(error){ console.log('Catch Error: A or B', error); } function finalTask(){ console.log('Final Task'); } var promise = Promise.resolve(); promise.then(taskA) .then(taskB) .catch(onRejected) .then(finalTask);
TaskA
TaskB
FinalTask
onRejected
function taskA(){ console.log('Task A'); return Promise.reject(new Error(…)); }
Promise.prototype.then
결과 값 전달
어떤����������� ������������������ onFulfilled의����������� ������������������ 반환����������� ������������������ 값은����������� ������������������ ����������� ������������������ 다음����������� ������������������ onFulfilled에����������� ������������������ 인자로����������� ������������������ 전달된다.����������� ������������������
31
Promise.prototype.then
결과 값 전달
어떤����������� ������������������ onFulfilled의����������� ������������������ 반환����������� ������������������ 값은����������� ������������������ ����������� ������������������ 다음����������� ������������������ onFulfilled에����������� ������������������ 인자로����������� ������������������ 전달된다.����������� ������������������
32
function doubleUp(value){ return value * 2; } function increment(value){ return value + 1; } function output(value){ console.log(value); } var promise = Promise.resolve(1); promise.then(increment) .then(doubleUp) .then(output);
increment
doubleUp
output
1
2
4
Promise.prototype.then
결과 값 전달
어떤����������� ������������������ onFulfilled의����������� ������������������ 반환����������� ������������������ 값은����������� ������������������ ����������� ������������������ 다음����������� ������������������ onFulfilled에����������� ������������������ 인자로����������� ������������������ 전달된다.����������� ������������������
33
function doubleUp(value){ return value * 2; } function increment(value){ return value + 1; } function output(value){ console.log(value); } var promise = Promise.resolve(1); promise.then(increment) .then(doubleUp) .then(output);
increment
doubleUp
output
1
2
4
반환����������� ������������������ 값으로는����������� ������������������ 숫자,����������� ������������������ 문자열,����������� ������������������ 객체뿐����������� ������������������ 아니라����������� ������������������ Promise도����������� ������������������
가능하다.����������� ������������������ 내부����������� ������������������ 적으로는����������� ������������������ Promise.resolve(반환����������� ������������������ 값)처럼����������� ������������������
처리����������� ������������������ 되기����������� ������������������ 떄문에����������� ������������������ 무엇을����������� ������������������ 반환하더라도����������� ������������������ 최종적으로는����������� ������������������
새로운����������� ������������������ promise����������� ������������������ 객체가����������� ������������������ 반환된다.����������� ������������������ 즉,����������� ������������������ then()은����������� ������������������ 단순히����������� ������������������
콜백����������� ������������������ 함수를����������� ������������������ 등록하기만����������� ������������������ 하는게����������� ������������������ 아니라����������� ������������������ 콜백에서����������� ������������������ 반환한����������� ������������������
값을����������� ������������������ 기준으로����������� ������������������ 새로운����������� ������������������ promise����������� ������������������ 객체를����������� ������������������ 생성해����������� ������������������ 전달하는����������� ������������������
기능도����������� ������������������ 하고����������� ������������������ 있다.����������� ������������������ ����������� ������������������
function increment(value){ return Promise.resolve(value + 1); }
Promise.prototype.then
복수의 비동기 요청 - callback
then을����������� ������������������ 이용해����������� ������������������ 복수의����������� ������������������ 비동기����������� ������������������ 요청을����������� ������������������ 구현하는����������� ������������������ 방법에����������� ������������������ 대해����������� ������������������ 소개한다.����������� ������������������ 먼저����������� ������������������ 전통적인����������� ������������������ 콜백����������� ������������������ 스타일로����������� ������������������ 이를����������� ������������������ 구현해����������� ������������������ 본다.����������� ������������������
34
Promise.prototype.then
복수의 비동기 요청 - callback
then을����������� ������������������ 이용해����������� ������������������ 복수의����������� ������������������ 비동기����������� ������������������ 요청을����������� ������������������ 구현하는����������� ������������������ 방법에����������� ������������������ 대해����������� ������������������ 소개한다.����������� ������������������ 먼저����������� ������������������ 전통적인����������� ������������������ 콜백����������� ������������������ 스타일로����������� ������������������ 이를����������� ������������������ 구현해����������� ������������������ 본다.����������� ������������������
35
function ajax(URL, callback){ var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function(){ if(req.status === 200){ callback(null, req.responseText); }else{ callback( new Error(req.statusText), req.response ); } }; req.onerror = function(){ callback(new Error(req.statusText)); }; req.send(); }
function jsonify(callback, error, value){ var result; if(error){ callback(error, value); }else{ try{ result = JSON.parse(value); callback(null, result); }catch(err){ callback(err, value); } } }
계속����������� ������������������ >>����������� ������������������
Promise.prototype.then
복수의 비동기 요청 - callback
then을����������� ������������������ 이용해����������� ������������������ 복수의����������� ������������������ 비동기����������� ������������������ 요청을����������� ������������������ 구현하는����������� ������������������ 방법에����������� ������������������ 대해����������� ������������������ 소개한다.����������� ������������������ 먼저����������� ������������������ 전통적인����������� ������������������ 콜백����������� ������������������ 스타일로����������� ������������������ 이를����������� ������������������ 구현해����������� ������������������ 본다.����������� ������������������
36
var request = { cards : function(callback){ return ajax('/api/cards', jsonify.bind(null, callback)); }, insurances : function(callback){ return ajax('/api/insurances', jsonify.bind(null, callback)); } };
function all(requests, record, callback){ var req; if(requests.length === 0){ return callback(null, record); } req = requests.shift(); req(function(error, value){ if(error){ callback(error, value); }else{ record.push(value); all(requests, record, callback); } }); }
all([request.cards, request.insurances], [], function(error, value){ if(error){ console.log(error); }else{ console.log(value); } });
Promise.prototype.then
복수의 비동기 요청 - then
전통적인����������� ������������������ 콜백����������� ������������������ 패턴이����������� ������������������ 가지고����������� ������������������ 있는����������� ������������������ 문제를����������� ������������������ then()으로����������� ������������������ 해결해보자.����������� ������������������ (이해를����������� ������������������ 돕기����������� ������������������ 위해����������� ������������������ then()을����������� ������������������ 사용하지만,����������� ������������������ 사실����������� ������������������ ����������� ������������������ 복수의����������� ������������������ 비동기����������� ������������������ 처리����������� ������������������ 시����������� ������������������ 유용한����������� ������������������ Promise.all()과����������� ������������������ Promise.race()가����������� ������������������ 있다.)����������� ������������������
37
Promise.prototype.then
복수의 비동기 요청 - then
전통적인����������� ������������������ 콜백����������� ������������������ 패턴이����������� ������������������ 가지고����������� ������������������ 있는����������� ������������������ 문제를����������� ������������������ then()으로����������� ������������������ 해결해보자.����������� ������������������ (이해를����������� ������������������ 돕기����������� ������������������ 위해����������� ������������������ then()을����������� ������������������ 사용하지만,����������� ������������������ 사실����������� ������������������ ����������� ������������������ 복수의����������� ������������������ 비동기����������� ������������������ 처리����������� ������������������ 시����������� ������������������ 유용한����������� ������������������ Promise.all()과����������� ������������������ Promise.race()가����������� ������������������ 있다.)����������� ������������������
38
function ajax(URL){ return new Promise(function(resolve, reject){ var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function(){ if(req.status === 200){ resolve(req.responseText); }else{ reject(new Error(req.statusText)); } }; req.onerror = function(){ reject(new Error(req.statusText)); }; req.send(); }) }
var request = { cards : function(){ return ajax('/api/cards') .then(JSON.parse) }, insurances : function(){ return ajax('/api/insurances') .then(JSON.parse) } };
Promise.prototype.then
복수의 비동기 요청 - then
전통적인����������� ������������������ 콜백����������� ������������������ 패턴이����������� ������������������ 가지고����������� ������������������ 있는����������� ������������������ 문제를����������� ������������������ then()으로����������� ������������������ 해결해보자.����������� ������������������ (이해를����������� ������������������ 돕기����������� ������������������ 위해����������� ������������������ then()을����������� ������������������ 사용하지만,����������� ������������������ 사실����������� ������������������ ����������� ������������������ 복수의����������� ������������������ 비동기����������� ������������������ 처리����������� ������������������ 시����������� ������������������ 유용한����������� ������������������ Promise.all()과����������� ������������������ Promise.race()가����������� ������������������ 있다.)����������� ������������������
39
function all(){ var record = []; function recording(value){ record.push(value); return record; } return request.cards().then(recording) .then(request.insurances).then(recording); }
all().then(function(value){ console.log(value); }).catch(function(error){ console.log(error); });
Promise.prototype.catch
IE에서의 문제
전catch()는����������� ������������������ Promise.then(undefined,����������� ������������������ onRejected)를����������� ������������������ 랩핑한����������� ������������������ 메서드다.����������� ������������������ promise����������� ������������������ 객체가����������� ������������������ Rejected����������� ������������������ 상태가����������� ������������������ 됐을����������� ������������������ 때����������� ������������������ 호출될����������� ������������������ 콜백����������� ������������������ 함수를����������� ������������������ 등록하기����������� ������������������ 위해����������� ������������������ 사용한다.����������� ������������������
40
위는����������� ������������������ polyfill을����������� ������������������ 사용한����������� ������������������ 상태에서����������� ������������������ Promise����������� ������������������ 동작����������� ������������������ 여부를����������� ������������������ 테스트한����������� ������������������ ����������� ������������������
사진이다.����������� ������������������ IE8����������� ������������������ 이하����������� ������������������ 브라우저에서는����������� ������������������ “식별자를����������� ������������������ 찾을����������� ������������������ 수����������� ������������������ 없습니다”����������� ������������������
라는����������� ������������������ 메시지와����������� ������������������ 함께����������� ������������������ Syntac����������� ������������������ Error가����������� ������������������ 발생한다.����������� ������������������
var promise = Promise.reject(new Error('message')); promise.catch(function(error){ console.log(error.message); });
var promise = Promise.reject(new Error('message')); promise['catch'](function(error){ console.log(error.message); });
var promise = Promise.reject(new Error('message')); promise.then(undefined, function(error){ console.log(error.message); });
ECMAScript3에서는����������� ������������������ 예약어를����������� ������������������ 객체의����������� ������������������ 프로퍼티����������� ������������������ 명으로����������� ������������������ 사용할����������� ������������������
수����������� ������������������ 없다.����������� ������������������ IE8이하����������� ������������������ 버전은����������� ������������������ ECMAScript3를����������� ������������������ 따를����������� ������������������ 브라우저이다.����������� ������������������
이런����������� ������������������ 문제를����������� ������������������ 미연에����������� ������������������ 방지하고자����������� ������������������ 일부����������� ������������������ 라이브러리는����������� ������������������ caught,����������� ������������������
fail����������� ������������������ 등과����������� ������������������ 같은����������� ������������������ 이름으로����������� ������������������ catch()와����������� ������������������ 동일한����������� ������������������ 기능을����������� ������������������ 하는����������� ������������������ 메서드를����������� ������������������
지원한다.����������� ������������������
Promise.all
복수의 비동기 요청 - all
복수의����������� ������������������ 비동기����������� ������������������ 로직은����������� ������������������ Promise.all()을����������� ������������������ 이용하면����������� ������������������ 간단하게����������� ������������������ 작성할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������
41
Promise.all
복수의 비동기 요청 - all
복수의����������� ������������������ 비동기����������� ������������������ 로직은����������� ������������������ Promise.all()을����������� ������������������ 이용하면����������� ������������������ 간단하게����������� ������������������ 작성할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������
42
Promise.all([ ajax('/api/cards').then(JSON.parse), ajax('/api/insurances').then(JSON.parse) ]).then(function(value){ console.log(value); }).catch(function(error){ console.log(error); });
Promise.all()는����������� ������������������ 인자로����������� ������������������ promise����������� ������������������ 객체를����������� ������������������ 원소로����������� ������������������ 가진����������� ������������������ 배열을����������� ������������������ 받는다.����������� ������������������
처리가����������� ������������������ 완료된����������� ������������������ 후����������� ������������������ 값����������� ������������������ 순서는����������� ������������������ 배열의����������� ������������������ 순서와����������� ������������������ 같다.����������� ������������������
����������� ������������������
하나����������� ������������������ 명심해야할����������� ������������������ 점은����������� ������������������ Promise.all()은����������� ������������������ 복수의����������� ������������������ 비동기����������� ������������������ 로직을����������� ������������������ 순차적����������� ������������������ ����������� ������������������
실행하지����������� ������������������ 않고����������� ������������������ 동시에����������� ������������������ 실행한다는����������� ������������������ 점이다.����������� ������������������
function timer(delay){ return new Promise(function(resolve){ setTimeout(function(){ resolve(delay); }, delay); }) } var start = Date.now(); Promise.all([ timer(1), timer(32), timer(64), timer(128) ]).then(function(values){ console.log(Date.now() - start + 'ms'); console.log(values); });
Promise.race
복수의 비동기 요청 - race
Promise.all()과����������� ������������������ 마찬가지로����������� ������������������ promise����������� ������������������ 객체를����������� ������������������ 배열로����������� ������������������ 전달����������� ������������������ 받아����������� ������������������ ����������� ������������������ 복수의����������� ������������������ 비동기����������� ������������������ 로직을����������� ������������������ 처리한다.����������� ������������������ ����������� ������������������ Promise.race()는����������� ������������������ Promise.all()과����������� ������������������ 달리����������� ������������������ promise����������� ������������������ 객체����������� ������������������ 중����������� ������������������ 하나����������� ������������������ 만����������� ������������������ 완료돼도����������� ������������������ 다음����������� ������������������ 동작으로����������� ������������������ 넘어간다.����������� ������������������
43
Promise.race
복수의 비동기 요청 - race
Promise.all()과����������� ������������������ 마찬가지로����������� ������������������ promise����������� ������������������ 객체를����������� ������������������ 배열로����������� ������������������ 전달����������� ������������������ 받아����������� ������������������ ����������� ������������������ 복수의����������� ������������������ 비동기����������� ������������������ 로직을����������� ������������������ 처리한다.����������� ������������������ ����������� ������������������ Promise.race()는����������� ������������������ Promise.all()과����������� ������������������ 달리����������� ������������������ promise����������� ������������������ 객체����������� ������������������ 중����������� ������������������ 하나����������� ������������������ 만����������� ������������������ 완료돼도����������� ������������������ 다음����������� ������������������ 동작으로����������� ������������������ 넘어간다.����������� ������������������
44
function timer(delay){ return new Promise(function(resolve){ setTimeout(function(){ resolve(delay); }, delay); }) } var start = Date.now(); Promise.race([ timer(1), timer(32), timer(64), timer(128) ]).then(function(values){ console.log(Date.now() - start + 'ms'); console.log(values); });
PROMISES의 특징
항상 비동기로 처리되는 Promise
항상 비동기로 처리
46
Promise.resolve()나����������� ������������������ resolve()를����������� ������������������ 사용하면����������� ������������������ promise����������� ������������������ 객체는����������� ������������������ 바로����������� ������������������ Fulfilled����������� ������������������ 상태가����������� ������������������ 되므로����������� ������������������ then()으로����������� ������������������ 등록한����������� ������������������ 콜백����������� ������������������ 함수도����������� ������������������ 동기적으로����������� ������������������ 호출될����������� ������������������ 것이라����������� ������������������ 예상된다.����������� ������������������
항상 비동기로 처리되는 Promise
항상 비동기로 처리
Promise.resolve()나����������� ������������������ resolve()를����������� ������������������ 사용하면����������� ������������������ promise����������� ������������������ 객체는����������� ������������������ 바로����������� ������������������ Fulfilled����������� ������������������ 상태가����������� ������������������ 되므로����������� ������������������ then()으로����������� ������������������ 등록한����������� ������������������ 콜백����������� ������������������ 함수도����������� ������������������ 동기적으로����������� ������������������ 호출될����������� ������������������ 것이라����������� ������������������ 예상된다.����������� ������������������
47
var promise = new Promise(function(resolve){ console.log('inner promise'); resolve(42); }); promise.then(function(value){ console.log(value); }); console.log('outer promise');
노트����������� ������������������ :����������� ������������������ ES6����������� ������������������ Promises����������� ������������������ 사양에는����������� ������������������ promise����������� ������������������ 객체의����������� ������������������ 상태가����������� ������������������ 이미����������� ������������������ 정해져����������� ������������������ 있다����������� ������������������ 하더라도����������� ������������������ 비동기로����������� ������������������ 처리����������� ������������������ 돼야����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 한다고����������� ������������������ 정하고����������� ������������������ 있다.����������� ������������������
항상 비동기로 처리되는 Promise
동기와 비동기 혼재의 위험성
데이터를����������� ������������������ 즉시����������� ������������������ 사용할����������� ������������������ 수����������� ������������������ 있더라도����������� ������������������ 절대로����������� ������������������ 비동기����������� ������������������ 콜백을����������� ������������������ 동기적으로����������� ������������������ 호출하면����������� ������������������ 안된다.����������� ������������������ 비동기����������� ������������������ 콜백을����������� ������������������ 동기적으로����������� ������������������ 호출하면����������� ������������������ 기대한����������� ������������������ 연산의����������� ������������������ 순서를����������� ������������������ 방해하고����������� ������������������ 예상치����������� ������������������ 않은����������� ������������������ 코드의����������� ������������������ 간섭을����������� ������������������ 초래할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ -����������� ������������������ 이펙티브����������� ������������������ 자바스크립트����������� ������������������ -����������� ������������������
48
function onReady(callback){ var readyState = document.readyState; if(readyState === 'interactive' || readyState === 'complete'){ callback(); }else{ window.addEventListener( 'DOMContentLoaded', callback ); } } onReady(function(){ console.log('DOM fully loaded and parsed'); }); console.log('starting...');
if(readyState === 'interactive' || readyState === 'complete'){ setTimeout(fn, 0) }else{
function onReady(){ return new Promise(function(resolve){ var readyState = document.readyState; if(readyState === 'interactive' || readyState === 'complete'){ resolve(); }else{ window.addEventListener( 'DOMContentLoaded', resolve); } }); } onReady().then(function(){ console.log('DOM fully loaded and parsed'); }); console.log('starting...');
새로운 promise 객체를 반환하는 then
새로운 promise 객체를 반환
Promise����������� ������������������ 로직을����������� ������������������ 보면����������� ������������������ 모두����������� ������������������ 최초의����������� ������������������ promise����������� ������������������ 객체에����������� ������������������ 메서드를����������� ������������������ 체인하는����������� ������������������ 것����������� ������������������ 처럼����������� ������������������ 보인다.����������� ������������������ 하지만����������� ������������������ 실제로는����������� ������������������ then()과����������� ������������������ catch()����������� ������������������ 모두����������� ������������������ 새로운����������� ������������������ promise����������� ������������������ 객체를����������� ������������������ 생성해����������� ������������������ 반환한다.����������� ������������������
49
새로운 promise 객체를 반환하는 then
새로운 promise 객체를 반환
Promise����������� ������������������ 로직을����������� ������������������ 보면����������� ������������������ 모두����������� ������������������ 최초의����������� ������������������ promise����������� ������������������ 객체에����������� ������������������ 메서드를����������� ������������������ 체인하는����������� ������������������ 것����������� ������������������ 처럼����������� ������������������ 보인다.����������� ������������������ 하지만����������� ������������������ 실제로는����������� ������������������ then()과����������� ������������������ catch()����������� ������������������ 모두����������� ������������������ 새로운����������� ������������������ promise����������� ������������������ 객체를����������� ������������������ 생성해����������� ������������������ 반환한다.����������� ������������������
50
var promise = new Promise(function(resolve){ resolve(100); }); var thenPromise = promise.then(function(value){ console.log(value); }); var catchPromise = thenPromise.catch(function(error){ console.log(error); }); console.log(promise === thenPromise); console.log(thenPromise === catchPromise);
onFulfilled
onRejected onRejected
promise object promise object value
error error
then catch
새로운 promise 객체를 반환하는 then
새로운 promise 객체를 반환
Promise����������� ������������������ 로직을����������� ������������������ 보면����������� ������������������ 모두����������� ������������������ 최초의����������� ������������������ promise����������� ������������������ 객체에����������� ������������������ 메서드를����������� ������������������ 체인하는����������� ������������������ 것����������� ������������������ 처럼����������� ������������������ 보인다.����������� ������������������ 하지만����������� ������������������ 실제로는����������� ������������������ then()과����������� ������������������ catch()����������� ������������������ 모두����������� ������������������ 새로운����������� ������������������ promise����������� ������������������ 객체를����������� ������������������ 생성해����������� ������������������ 반환한다.����������� ������������������
51
var promise = new Promise(function(resolve){ resolve(100); }); promise.then(function(value){ return value * 2; }); promise.then(function(value){ return value * 2; }); promise.then(function(value){ console.log(value); // 100 });
var promise = new Promise(function(resolve){ resolve(100); }); promise.then(function(value){ return value * 2; }).then(function(value){ return value * 2; }).then(function(value){ console.log(value); // 100 * 2 * 2 });
function anAsyncCall(){ var promise = Promise.resolve(); promise.then(function(){ // something do... }); return promise; }
예외 처리가 되지 않는 onRejected
예외 처리가 되지 않는 경우
then()을����������� ������������������ 이용해����������� ������������������ onFulfilled와����������� ������������������ onRejected를����������� ������������������ 모두����������� ������������������ 등록한다면����������� ������������������ 예외����������� ������������������ 처리가����������� ������������������ 되지����������� ������������������ 않는����������� ������������������ 상황이����������� ������������������ 발생한다.����������� ������������������
52
예외 처리가 되지 않는 onRejected
예외 처리가 되지 않는 경우
then()을����������� ������������������ 이용해����������� ������������������ onFulfilled와����������� ������������������ onRejected를����������� ������������������ 모두����������� ������������������ 등록한다면����������� ������������������ 예외����������� ������������������ 처리가����������� ������������������ 되지����������� ������������������ 않는����������� ������������������ 상황이����������� ������������������ 발생한다.����������� ������������������
53
Promise.resolve(30).then(function(value){ throw new Error(value); }, function(error){ console.log('BAD'); console.log(error); }); Promise.resolve(20).then(function(value){ throw new Error(value); }).catch(function(error){ console.log('GOOD'); console.log(error); }); Promise.resolve(10).then(function(value){ throw new Error(value); }).then(undefined, function(error){ console.log('OK'); console.log(error); });
콜백-헬과 무관한 Promise
만능의 도구가 아니다.
Promise는����������� ������������������ 콜백-헬을����������� ������������������ 해결할����������� ������������������ 수����������� ������������������ 있는����������� ������������������ 만능의����������� ������������������ 도구가����������� ������������������ 아니다.����������� ������������������ 통일된����������� ������������������ 인터페이스로����������� ������������������ 데이터를����������� ������������������ 전달할����������� ������������������ 수����������� ������������������ 있는����������� ������������������ 컨테이너로써����������� ������������������ 장점을����������� ������������������ 발휘하는����������� ������������������ 것이다.����������� ������������������
54
?����������� ������������������
콜백-헬과 무관한 Promise
만능의 도구가 아니다.
Promise는����������� ������������������ 콜백-헬을����������� ������������������ 해결할����������� ������������������ 수����������� ������������������ 있는����������� ������������������ 만능의����������� ������������������ 도구가����������� ������������������ 아니다.����������� ������������������ 통일된����������� ������������������ 인터페이스로����������� ������������������ 데이터를����������� ������������������ 전달할����������� ������������������ 수����������� ������������������ 있는����������� ������������������ 컨테이너로써����������� ������������������ 장점을����������� ������������������ 발휘하는����������� ������������������ 것이다.����������� ������������������
55
some().then(function(){ // do something... }).then(function(){ // do something... }).then(function(){ // do something... }).then(function(){ // do something... }).catch(function(){ // do something... });
콜백-헬과 무관한 Promise
만능의 도구가 아니다.
콜백-헬에����������� ������������������ 빠진����������� ������������������ 상태라면����������� ������������������ 분석한����������� ������������������ 모델이����������� ������������������ 이미����������� ������������������ 깨져있고,����������� ������������������ 관심사를����������� ������������������ 제대로����������� ������������������ 나누지����������� ������������������ 않았다는����������� ������������������ 방증이다.����������� ������������������ ����������� ������������������ 이는����������� ������������������ Promise로도����������� ������������������ 해결할����������� ������������������ 수����������� ������������������ 없다.����������� ������������������
56
커넥터 로직 비즈니스 로직 엔티티 로직 서비스 로직 DAO 로직
스토리지
엔티티 (DTO)
DAO
커넥터
비즈니스
서비스
값 객체
콜백-헬과 무관한 Promise
설계
• 사용자가����������� ������������������ /api/stores����������� ������������������ 를����������� ������������������ GET����������� ������������������ 요청하면����������� ������������������ 상점����������� ������������������ 리스트를����������� ������������������ 반환한다.����������� ������������������ • 사용자가����������� ������������������ /api/stores/:id����������� ������������������ 를����������� ������������������ GET����������� ������������������ 요청하면����������� ������������������ 상점을����������� ������������������ 반환한다.����������� ������������������ • 데이터베이스엔����������� ������������������ 상점����������� ������������������ 테이블과����������� ������������������ 카테고리����������� ������������������ 테이블이����������� ������������������ 별도로����������� ������������������ 존재한다.����������� ������������������
57
콜백-헬과 무관한 Promise
설계
• 사용자가����������� ������������������ /api/stores����������� ������������������ 를����������� ������������������ GET����������� ������������������ 요청하면����������� ������������������ 상점����������� ������������������ 리스트를����������� ������������������ 반환한다.����������� ������������������ • 사용자가����������� ������������������ /api/stores/:id����������� ������������������ 를����������� ������������������ GET����������� ������������������ 요청하면����������� ������������������ 상점을����������� ������������������ 반환한다.����������� ������������������ • 데이터베이스엔����������� ������������������ 상점����������� ������������������ 테이블과����������� ������������������ 카테고리����������� ������������������ 테이블이����������� ������������������ 별도로����������� ������������������ 존재한다.����������� ������������������
58
Stores
Categories
DB Connector
Market client
콜백-헬과 무관한 Promise
Store 클래스
Store����������� ������������������ 클래스를����������� ������������������ 작성한다.����������� ������������������
59
콜백-헬과 무관한 Promise
Store 클래스
Store����������� ������������������ 클래스를����������� ������������������ 작성한다.����������� ������������������
60
var Stores = function(connector){ this._connector = connector; }; Stores.prototype = { findAll : function(){ var self = this; return new Promise(function(resolve){ var stores = self._connector.where(); resolve(stores.items); }) }, findBy : function(id){ var self = this; return new Promise(function(resolve, reject){ var store = self._connector.get(parseInt(id, 10)); if(store){ resolve(store); }else{ reject(new Error('Not Found.')); } }); } }; module.exports = Stores;
콜백-헬과 무관한 Promise
Categories 클래스
Categories����������� ������������������ 클래스����������� ������������������ 작성하기����������� ������������������
61
콜백-헬과 무관한 Promise
Categories 클래스
Categories����������� ������������������ 클래스����������� ������������������ 작성하기����������� ������������������
62
var Categories = function(connector){ this._connector = connector; }; Categories.prototype = { findAll : function(){ var self = this; return new Promise(function(resolve){ var categories = self._connector.where(); resolve(categories.items); }) }, findBy : function(id){ var self = this; return new Promise(function(resolve, reject){ var category = self._connector.where({_id : id}).items[0]; if(category){ resolve(category); }else{ reject(new Error('Not Found.')); } }); } }; module.exports = Categories;
콜백-헬과 무관한 Promise
Market 클래스
Market����������� ������������������ 클래스����������� ������������������ 작성하기����������� ������������������
63
콜백-헬과 무관한 Promise
Market 클래스
Market����������� ������������������ 클래스����������� ������������������ 작성하기����������� ������������������
64
var Market = function(){ this._stores = new Stores(db.collection('stores')); this._categories = new Categories(db.collection('categories')); }; Market.prototype = { stores : function(){ return Promise.all([ this._stores.findAll(), this._categories.findAll() ]).then(function(values){ var stores = values[0], categories = values[1]; stores.forEach(function(store){ store.category = categories.find(function(category){ return category._id === store.category_id; }); }); return stores; }) },
계속����������� ������������������ >>����������� ������������������
콜백-헬과 무관한 Promise
Market 클래스
Market����������� ������������������ 클래스����������� ������������������ 작성하기����������� ������������������
65
store : function(id){ var self = this, store = null; return this._stores.findBy(id).then(function(values){ store = values; return self._categories.findBy(store.category_id); }).then(function(category){ store.category = category; return store; }); } }; module.exports = Market;
콜백-헬과 무관한 Promise
최종
app.js에서����������� ������������������ Market����������� ������������������ 객체����������� ������������������ 사용하기����������� ������������������
66
router.route('/stores').get(function(req, res) { market.stores().then(function(stores){ res.json(stores); }).catch(function(err){ res.writeHead(404, {"Content-Type": "text/plain"}); res.end(err.message); }) }); router.route('/stores/:id').get(function(req, res) { market.store(req.params.id).then(function(store){ res.json(store); }).catch(function(err){ res.writeHead(404, {"Content-Type": "text/plain"}); res.end(err.message); }) });
Promises 직접 구현하기
시작하기 전에
핵심
68
function doSomething(callback){ var value = 42; callback(null, value); }
doSomething(function(error, value){ console.log('Got a value : ', value); });
function doSomething(){ return { then : function(callback){ var value = 42; callback(value); } } }
doSomething().then(function(value){ console.log('Got a value : ', value); });
전통적인 콜백 패턴을 단순하게 변환한 것으로 큰 의미는 없어 보이지만, Promise의 근본적인 철학은 이미 다루고 있다.
Promise는 객체 내에 처리 결과를 보유한다.
Promise는 결과 값을 추상화한 객체를 전달한다.
스텝 1
Promise 클래스 정의
69
new����������� ������������������ 연산자를����������� ������������������ 사용해����������� ������������������ Promise����������� ������������������ 인스턴스를����������� ������������������ 생성할����������� ������������������ 수����������� ������������������ 있어야����������� ������������������ 하므로����������� ������������������ 클래스를����������� ������������������ 정의한다.����������� ������������������
스텝 1
Promise 클래스 정의
70
new����������� ������������������ 연산자를����������� ������������������ 사용해����������� ������������������ Promise����������� ������������������ 인스턴스를����������� ������������������ 생성할����������� ������������������ 수����������� ������������������ 있어야����������� ������������������ 하므로����������� ������������������ 클래스를����������� ������������������ 정의한다.����������� ������������������
var Promise = function(fn){ this._onFulfilled = null; fn(this._resolve.bind(this)); }; Promise.prototype = { then : function(onFulfilled){ this._onFulfilled = onFulfilled; }, _resolve : function(value){ this._onFulfilled(value); } };
스텝 1
Promise 클래스 정의
71
앞����������� ������������������ 슬라이드에서����������� ������������������ 구현한����������� ������������������ 코드는����������� ������������������ 동작하지����������� ������������������ 않는다.����������� ������������������ resolve()가����������� ������������������ then()보다����������� ������������������ 먼저����������� ������������������ 호출되어����������� ������������������ 그����������� ������������������ 결과����������� ������������������ _onFulfilled는����������� ������������������ null이����������� ������������������ 되어버리기����������� ������������������ 때문이다.����������� ������������������ 이����������� ������������������ 문제를����������� ������������������ 회피하기����������� ������������������ 위해����������� ������������������ ����������� ������������������ setTimeout()을����������� ������������������ 사용한다.����������� ������������������ ����������� ������������������
스텝 1
Promise 클래스 정의
72
앞����������� ������������������ 슬라이드에서����������� ������������������ 구현한����������� ������������������ 코드는����������� ������������������ 동작하지����������� ������������������ 않는다.����������� ������������������ resolve()가����������� ������������������ then()보다����������� ������������������ 먼저����������� ������������������ 호출되어����������� ������������������ 그����������� ������������������ 결과����������� ������������������ _onFulfilled는����������� ������������������ null이����������� ������������������ 되어버리기����������� ������������������ 때문이다.����������� ������������������ 이����������� ������������������ 문제를����������� ������������������ 회피하기����������� ������������������ 위해����������� ������������������ ����������� ������������������ setTimeout()을����������� ������������������ 사용한다.����������� ������������������ ����������� ������������������
_resolve : function(value){ + var self = this;
+ setTimeout(function(){ self._onFulfilled(value); + }.bind(this), 1); }
스텝 2
fulfilled 상태와 resolve
73
setTimeout()은����������� ������������������ 한계가����������� ������������������ 있다.����������� ������������������ then()을����������� ������������������ 비동기로����������� ������������������ 호출하면����������� ������������������ 다시����������� ������������������ _onFulfilled는����������� ������������������ null이����������� ������������������ 된다.����������� ������������������ Promise에는����������� ������������������ 상태가����������� ������������������ 있다.����������� ������������������ 이����������� ������������������ 상태를����������� ������������������ 이용하면����������� ������������������ setTimeout을����������� ������������������ 제거하면서����������� ������������������ 동기/비동기에����������� ������������������ 상관없이����������� ������������������ then()을����������� ������������������ 호출할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������ ����������� ������������������
스텝 2
fulfilled 상태와 resolve
74
setTimeout()은����������� ������������������ 한계가����������� ������������������ 있다.����������� ������������������ then()을����������� ������������������ 비동기로����������� ������������������ 호출하면����������� ������������������ 다시����������� ������������������ _onFulfilled는����������� ������������������ null이����������� ������������������ 된다.����������� ������������������ Promise에는����������� ������������������ 상태가����������� ������������������ 있다.����������� ������������������ 이����������� ������������������ 상태를����������� ������������������ 이용하면����������� ������������������ setTimeout을����������� ������������������ 제거하면서����������� ������������������ 동기/비동기에����������� ������������������ 상관없이����������� ������������������ then()을����������� ������������������ 호출할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������ ����������� ������������������ var Promise = function(fn){ + this._state = 'pending'; + this._value = null; + this._deferred = null; this._onFulfilled = null; ... Promise.prototype = { then : function(onFulfilled){- this._onFulfilled = onFulfilled; + this._handle(onFulfilled); },
_resolve : function(value){ - setTimeout(function(){ - this._onFulfilled(value); - }.bind(this), 1);
+ this._value = value; + this._state = 'fulfilled';
+ if(this._deferred){ + this._handle(this._deferred); + } },
계속����������� ������������������ >>����������� ������������������
스텝 2
fulfilled 상태와 resolve
75
setTimeout()은����������� ������������������ 한계가����������� ������������������ 있다.����������� ������������������ then()을����������� ������������������ 비동기로����������� ������������������ 호출하면����������� ������������������ 다시����������� ������������������ _onFulfilled는����������� ������������������ null이����������� ������������������ 된다.����������� ������������������ Promise에는����������� ������������������ 상태가����������� ������������������ 있다.����������� ������������������ 이����������� ������������������ 상태를����������� ������������������ 이용하면����������� ������������������ setTimeout을����������� ������������������ 제거하면서����������� ������������������ 동기/비동기에����������� ������������������ 상관없이����������� ������������������ then()을����������� ������������������ 호출할����������� ������������������ 수����������� ������������������ 있다.����������� ������������������ ����������� ������������������
+ _handle : function(onFulfilled){ + if(this._state === 'pending'){ + this._deferred = onFulfilled; + return false; + } + onFulfilled(this._value); + } };
스텝 3
Promise의 체이닝
76
Promise의����������� ������������������ 상태는����������� ������������������ 한번����������� ������������������ 변화하면����������� ������������������ 더이상����������� ������������������ 변하지����������� ������������������ 않는다.����������� ������������������ 이����������� ������������������ 조건을����������� ������������������ 고려하여����������� ������������������ Promise����������� ������������������ 체이닝을����������� ������������������ 구현한다.����������� ������������������
스텝 3
Promise의 체이닝
77
Promise의����������� ������������������ 상태는����������� ������������������ 한번����������� ������������������ 변화하면����������� ������������������ 더이상����������� ������������������ 변하지����������� ������������������ 않는다.����������� ������������������ 이����������� ������������������ 조건을����������� ������������������ 고려하여����������� ������������������ Promise����������� ������������������ 체이닝을����������� ������������������ 구현한다.����������� ������������������
var Promise = function(fn){ ... - this._onFulfilled = null; ... Promise.prototype = { then : function(onFulfilled){ - this._handle(onFulfilled); + var self = this;
+ return new Promise(function(resolve){ + self._handle({ + onFulfilled : onFulfilled, + resolve : resolve + }); + }.bind(this)); }, _resolve : function(value){ ... },
_handle : function(handler){ if(this._state === 'pending'){ this._deferred = handler; return false; } + var result = handler.onFulfilled(this._value); + handler.resolve(result); - onFulfilled(this._value); } };
스텝 3
Promise의 체이닝
78
then()의����������� ������������������ callback����������� ������������������ 전달인자는����������� ������������������ 옵셔널하게����������� ������������������ 한다.����������� ������������������
_handle : function(handler){ if(this._state === 'pending'){ this._deferred = handler; return false; } + if(!handler.onFulfilled){ + handler.resolve(this._value); + return false; + } var result = handler.onFulfilled(this._value); handler.resolve(result); }
스텝 3
Promise의 체이닝
79
then()으로����������� ������������������ 등록한����������� ������������������ 콜백은����������� ������������������ 값����������� ������������������ 뿐만����������� ������������������ 아니라����������� ������������������ Promise����������� ������������������ 객체도����������� ������������������ 전달할����������� ������������������ 수����������� ������������������ 있어야����������� ������������������ 한다.����������� ������������������ 그리고����������� ������������������ 그����������� ������������������ 객체가����������� ������������������ 해결한����������� ������������������ 값이����������� ������������������ 다음����������� ������������������ 처리에����������� ������������������ 전달된다.����������� ������������������
스텝 3
Promise의 체이닝
80
then()으로����������� ������������������ 등록한����������� ������������������ 콜백은����������� ������������������ 값����������� ������������������ 뿐만����������� ������������������ 아니라����������� ������������������ Promise����������� ������������������ 객체도����������� ������������������ 전달할����������� ������������������ 수����������� ������������������ 있어야����������� ������������������ 한다.����������� ������������������ 그리고����������� ������������������ 그����������� ������������������ 객체가����������� ������������������ 해결한����������� ������������������ 값이����������� ������������������ 다음����������� ������������������ 처리에����������� ������������������ 전달된다.����������� ������������������
resolve : function(value){ + if(value && typeof value.then === 'function'){ + value.then(this._resolve.bind(this)); + return false; + } this._state = 'fulfilled'; this._value = value; if(this._deferred){ this._handle(this._deferred); } },
스텝 4
rejected 상태와 reject
81
무엇인가����������� ������������������ 문제가����������� ������������������ 생긴����������� ������������������ 경우에는����������� ������������������ 원인과����������� ������������������ 함께����������� ������������������ 거부(reject)해야����������� ������������������ 한다.����������� ������������������
계속����������� ������������������ >>����������� ������������������
스텝 4
rejected 상태와 reject
82
무엇인가����������� ������������������ 문제가����������� ������������������ 생긴����������� ������������������ 경우에는����������� ������������������ 원인과����������� ������������������ 함께����������� ������������������ 거부(reject)해야����������� ������������������ 한다.����������� ������������������
var Promise = function(fn){ ... fn( this._resolve.bind(this), + this._reject.bind(this) ); }; Promise.prototype = { then : function(onFulfilled, onRejected){ return new Promise(function(resolve, reject){ this._handle({ onFulfilled : onFulfilled, + onRejected : onRejected, resolve : resolve, + reject : reject }); }.bind(this)) }, + _reject : function(error){ + this._state = 'rejected'; + this._value = error; + if(this._deferred){ + this._handle(this._deferred); + } + }, 계속����������� ������������������ >>����������� ������������������
스텝 4
rejected 상태와 reject
83
무엇인가����������� ������������������ 문제가����������� ������������������ 생긴����������� ������������������ 경우에는����������� ������������������ 원인과����������� ������������������ 함께����������� ������������������ 거부(reject)해야����������� ������������������ 한다.����������� ������������������
_handle : function(handler){ + var callback = null; ... + if(this._state === 'fulfilled'){ + callback = handler.onFulfilled; + }else{ + callback = handler.onRejected; + } + if(!callback){ + if(this._state === 'fulfilled'){ + handler.resolve(this._value); + }else{ + handler.reject(this._value); + } + return false; + }
var result = callback(this._value); ... };
스텝 4
예기치 못한 에러
84
Promise는����������� ������������������ 예상����������� ������������������ 밖의����������� ������������������ 예외를����������� ������������������ 대응하고����������� ������������������ 적절히����������� ������������������ 거부할����������� ������������������ 수����������� ������������������ 있어야����������� ������������������ 한다.����������� ������������������ var Promise = function(fn){ this._state = 'pending'; this._value = null; this._deferred = null; + try{ fn( this._resolve.bind(this), this._reject.bind(this) ); + }catch(error){ + this._reject(error); + } };
_handle : function(handler){ var callback = null, + result = null; ... + try{ + result = callback(this._value); + }catch(error){ + handler.reject(error); + return false; + } handler.resolve(result); }
스텝 5
항상 비동기로 호출
85
Promise는����������� ������������������ 항상����������� ������������������ 비동기로����������� ������������������ 호출돼야����������� ������������������ 한다.����������� ������������������
스텝 5
항상 비동기로 호출
86
Promise는����������� ������������������ 항상����������� ������������������ 비동기로����������� ������������������ 호출돼야����������� ������������������ 한다.����������� ������������������
_handle : function(handler){ var callback = null, result = null, + self = this; if(this._state === 'pending'){ this._deferred = handler; return false; } + setTimeout(function(){ ... + }, 0); }
<참고자료>
http://blog.coderifleman.com/post/102749244059
http://www.hanbit.co.kr/ebook/look.html?isbn=9788968487293����������� ������������������
http://www.mattgreer.org/articles/promises-in-wicked-detail/����������� ������������������
Thank you.