SlideShare a Scribd company logo
1 of 61
Download to read offline
Promise and Bluebird
Daniel Ku (http://danielku.com/)
PromiseJavascript 코드 가독성을 높이기 위한 위한 베스트 프랙티스
Promise 스펙: https://promisesaplus.com/
Bluebird가장 유명한 Promise 구현체 중 하나
https://github.com/petkaantonov/bluebird
Node.js 사용 시
이렇게 선언하게 한다.
var Promise = require('bluebird');
나는 보통 다음과 같이 선언한다.
var Q = require('bluebird');
이유: 짧으니까
맛보기
이러한 코드가 있다고 하자.
User.findOne({email: email}, function(err, user) {
if (err) {
console.error(err);
} else {
Group.find({owner: user.id}, function(err, groups) {
if (err) {
console.error(err);
} else {
try {
// do something with groups
console.log('success');
} catch (err) {
console.error(err);
}
}
});
});
문제점 1. 중첩된 콜백과 if절 등으로 가독성이 떨어진다.
User.findOne({email: email}, function(err, user) {
if (err) {
console.error(err);
} else {
Group.find({owner: user.id}, function(err, groups) {
if (err) {
console.error(err);
} else {
try {
// do something with groups
console.log('success');
} catch (err) {
console.error(err);
}
}
});
});
문제점 2. 동일한 에러 처리 로직이 중복되어 사용되었다.
User.findOne({email: email}, function(err, user) {
if (err) {
console.error(err);
} else {
Group.find({owner: user.id}, function(err, groups) {
if (err) {
console.error(err);
} else {
try {
// do something with groups
console.log('success');
} catch (err) {
console.error(err);
}
}
});
});
Promise를 이용해 바꾸어 보자. 더 길어지긴 했지만,
new Promise(function(resolve, reject) {
User.findOne({email: email}, function(err, user) {
if (err) reject(err);
else resolve(user);
});
})
.then(function(user) {
return new Promise(function(resolve, reject) {
Group.find({owner: user.id}, function(err, groups) {
if (err) reject(err);
else resolve(groups);
});
});
})
.then(function(groups) {
// do something with groups
})
.then(function() {
console.log('success');
})
.catch(function(err) {
console.error(err);
});
개선점 1. 작업의 단계가 명확히 구분된다.
new Promise(function(resolve, reject) {
User.findOne({email: email}, function(err, user) {
if (err) reject(err);
else resolve(user);
});
})
.then(function(user) {
return new Promise(function(resolve, reject) {
Group.find({owner: user.id}, function(err, groups) {
if (err) reject(err);
else resolve(groups);
});
});
})
.then(function(groups) {
// do something with groups
})
.then(function() {
console.log('success');
})
.catch(function(err) {
console.error(err);
});
개선점 2. 에러도 한군데에서 다 처리한다.
new Promise(function(resolve, reject) {
User.findOne({email: email}, function(err, user) {
if (err) reject(err);
else resolve(user);
});
})
.then(function(user) {
return new Promise(function(resolve, reject) {
Group.find({owner: user.id}, function(err, groups) {
if (err) reject(err);
else resolve(groups);
});
});
})
.then(function(groups) {
// do something with groups
})
.then(function() {
console.log('success');
})
.catch(function(err) {
console.error(err);
});
더 개선해 보자. 사용자를 찾는 부분을..
new Promise(function(resolve, reject) {
User.findOne({email: email}, function(err, user) {
if (err) reject(err);
else resolve(user);
});
});
다음과 같이 Wrapper 형태로 뽑아냈다고 가정해보자.
var UserWrapper = {
findOne: function(query) {
return new Promise(function(resolve, reject) {
User.findOne(query, function(err, user) {
if (err) reject(err);
else resolve(user);
});
});
}
};
그룹들을 찾는 부분도 마찬가지로..
var GroupWrapper = {
find: function(query) {
return new Promise(function(resolve, reject) {
Group.find(query, function(err, groups) {
if (err) reject(err);
else resolve(groups);
});
});
}
};
그러면 이런 식으로 바꿀 수 있다. 가독성이 훨씬 좋아졌다.
UserWrapper.findOne({ email: email })
.then(function(user) {
return GroupWrapper.find({ owner: user.id });
})
.then(function(groups) {
// do something with groups
})
.then(function() {
console.log('success');
})
.catch(function(err) {
console.error(err);
});
참고로 이러한 변환 과정을 Promisification이라고 하며,
Bluebird에서 제공하는 Promise.promisify() 함수를 이용하면
더 쉽게 할 수 있다.
극단적으로는 다음과도 같이 할 수 있다.
findUserByEmail(email)
.then(findOwningGroups)
.then(doSomethingWithGroups)
.then(whenSuccess)
.catch(whenFail);
주석이 필요없지 않은가? ㅋㅋ
시작, 중간 그리고 끝
시작: Promise Chain을 시작하는 방법
가장 쉬운 방법 중 하나는 Promise.defer() 함수를 이용하는 방
법이지만 deprecated되었다.
function dont_do_like_this() {
var deferred = Promise.defer();
doSomethingAsync(function(err, result) {
if (err) return deferred.reject(err);
deferred.resolve(result);
});
return deferred.promise;
}
그러므로 다음과 같이 Constructor를 이용하는 것이 더 바람직하
다.
function ok() {
return new Promise(function (resolve, reject) {
doSomethingAsync(function(err, result) {
if (err) return reject(err);
resolve(result);
});
});
}
Callback이 없다면 Promise.try() 함수를 이용할 수도 있다.
function checkSomething(something) {
return Promise.try(function () {
if (is_not_valid(something)) {
throw new Error('Something is not valid.');
}
return something;
});
}
로직 없이 주어진 값이나 오브젝트로 바로 Promise를 생성할 수도
있다.
function startWithValue(value) {
return Promise.resolve(value);
}
심지어 에러로 Promise를 생성할 수도 있다. 쓸 일이 있을까?
function startWithError(error) {
return Promise.reject(error);
}
중간: Promise Chain을 연결시키는 방법
Promise는 다음과 같이 .then() 함수와 .catch() 함수로 이어
나갈 수 있다.
ajaxGetAsync(url)
.then(function(result) {
return parseValueAsync(result);
})
.catch(function(error) {
console.error('error:', error);
});
직전 Promise의 결과 값과 상관 없이 특정 값으로 Promise
Chain을 이어가려면..
somethingAsync()
.return(value);
위는 아래와 같다.
somethingAsync()
.then(function() {
return value;
});
직전 Promise의 결과 값과 상관 없이 특정 에러로 Promise
Chain을 이어가려면..
somethingAsync()
.throw(reason);
위는 아래와 같다.
somethingAsync()
.then(function() {
throw reason;
});
.finally() 함수도 있다.
Promise.resolve('test')
.catch(console.error.bind(console))
.finally(function() {
return 'finally';
})
.then(function(result) {
console.log(result); // result is 'test'
});
끝: Promise Chain을 끝내는 방법
가장 간단한 방법은 더 이상 Promise Chain을 연결하지 않는 것
이다.
하지만 명시적으로 .done() 함수를 쓸 수 있다.
somethingAsync()
.done();
Alias
Promise.try() === Promise.attemp()
.catch() === .caught()
.return() === .thenReturn()
.throw() === .thenThrow()
.finally() === .lastly()
몇가지 안티 패턴
이렇게 하지 않도록 주의하라. (X)
somethingAsync()
.then(function(result) {
return anotherAsync(result);
}, function(err) {
handleError(err);
});
이렇게 해야 한다. (O)
somethingAsync()
.then(function(result) {
return anotherAsync(result);
})
.catch(function(err) {
handleError(err);
});
이렇게 하지 않도록 주의하라. (X)
var promise = somethingAsync();
if (is_another_necessary) {
promise.then(function(result) {
return anotherAsync(result);
});
}
promise.then(function(result) {
doSomethingWithResult(result);
});
이렇게 해야 한다. (O)
var promise = somethingAsync();
if (is_another_necessary) {
promise = promise.then(function(result) {
return anotherAsync(result);
});
}
promise.then(function(result) {
doSomethingWithResult(result);
});
편리한 유틸리티 함수들
.all()
.any()
.some()
.spread()
설명이 필요 없다.
Promise
.all([
pingAsync("ns1.example.com"),
pingAsync("ns2.example.com"),
pingAsync("ns3.example.com"),
pingAsync("ns4.example.com")
]).spread(function(first, second, third, fourth) {
console.log(first, second, third, fourth);
});
설명이 필요 없다.
Promise
.any([
pingAsync("ns1.example.com"),
pingAsync("ns2.example.com"),
pingAsync("ns3.example.com"),
pingAsync("ns4.example.com")
]).spread(function(first) {
console.log(first);
});
설명이 필요 없다.
Promise
.some([
pingAsync("ns1.example.com"),
pingAsync("ns2.example.com"),
pingAsync("ns3.example.com"),
pingAsync("ns4.example.com")
], 2).spread(function(first, second) {
console.log(first, second);
});
.map()
.reduce()
.filter()
.each()
설명이 필요 없다.
Group.listAsync({user: user.id})
.map(function(group) {
return group.removeAsync(user.id);
})
.then(function() {
return user.removeAsync();
});
설명이 필요 없다.
Group.listAsync({user: user.id})
.filter(function(group) {
return group.owner_id === user.id;
});
.map() 혹은 .filter()에서의 concurrency 제한에 대하여
Group.listAsync({user: user.id})
.map(function(group) {
return group.removeAsync(user.id);
}, {concurrency: 1});
참고로 하나씩 처리하려면 이렇게 할 수도 있다.
Group.listAsync({user: user.id})
.reduce(function(promise, group) {
return promise.then(function(groups) {
return group.removeAsync(user.id)
.then(function(group) {
groups.push(group);
})
.return(groups);
});
}, []);
(확인은 안 해봤지만 아마도 틀리지 않을 듯;;)
.delay()
설명이 필요 없다.
Promise
.delay(500)
.then(function() {
return 'Hello world';
})
.delay(500)
.then(function(result) {
console.log(result);
});
.tap()
Promise Chain을 연결하긴 하지만 결과를 넘겨주진 않음..
somethingAsync()
.tap(function(result_of_somethingAsync) {
return anotherAsync(result_of_somethingAsync);
})
.then(function(result_of_somethingAsync) {
console.log(result_of_somethingAsync);
});
.bind()
이런 식으로 앞의 결과를 나중에 써야할 경우엔 콜백에서처럼 가독
성이 떨어지는데..
somethingAsync()
.spread(function (a, b) {
return anotherAsync(a, b)
.then(function (c) {
return a + b + c;
});
});
이런 식으로도 해결할 수 있지만..
var scope = {};
somethingAsync()
.spread(function (a, b) {
scope.a = a;
scope.b = b;
return anotherAsync(a, b);
})
.then(function (c) {
return scope.a + scope.b + c;
});
이게 더 깔끔하다.
somethingAsync()
.bind({})
.spread(function (a, b) {
this.a = a;
this.b = b;
return anotherAsync(a, b);
})
.then(function (c) {
return this.a + this.b + c;
});
고급 예제
10초 마다 어떤 작업을 반복하도록 하려면?
10초 마다 어떤 작업을 반복하도록 하려면?
var loop = function() {
Worker.executeAsync()
.catch(function(err) {
console.error('err:', err);
})
.delay(10000)
.then(loop);
};
loop();
매우 긴 작업 목록을 10개씩 끊어서 처리하려면?
매우 긴 작업 목록을 10개씩 끊어서 처리하려면?
var traverseJobs = function(handleTenJobsAsync) {
var limit = 10;
var loop = function(skip) {
return listJobsAsync(limit, skip)
.then(function(jobs) {
if (jobs.length) {
return handleTenJobsAsync(jobs)
.then(function() {
return loop(skip + limit);
});
}
});
};
return loop(0);
};
못다한 고급 주제
— Resource Management
— Cancellation & .timeout()
— Built-in Errors
— Error Management configuration
— Generators
https://github.com/petkaantonov/bluebird/blob/
master/API.md
참고
— Bluebird
— Bluebird API Reference
— Promise Anti-patterns
THE END

More Related Content

What's hot

[하코사세미나]미리보는 대규모 자바스크립트 어플리케이션 개발
[하코사세미나]미리보는 대규모 자바스크립트 어플리케이션 개발[하코사세미나]미리보는 대규모 자바스크립트 어플리케이션 개발
[하코사세미나]미리보는 대규모 자바스크립트 어플리케이션 개발정석 양
 
발렌타인 웨비너 7회 - React를 이용한 웹 앱 개발 살펴보기
발렌타인 웨비너 7회 - React를 이용한 웹 앱 개발 살펴보기발렌타인 웨비너 7회 - React를 이용한 웹 앱 개발 살펴보기
발렌타인 웨비너 7회 - React를 이용한 웹 앱 개발 살펴보기DoHyun Jung
 
ReactJS로 시작하는 멀티플랫폼 개발하기
ReactJS로 시작하는 멀티플랫폼 개발하기ReactJS로 시작하는 멀티플랫폼 개발하기
ReactJS로 시작하는 멀티플랫폼 개발하기Taegon Kim
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSCirculus
 
React 튜토리얼 1차시
React 튜토리얼 1차시React 튜토리얼 1차시
React 튜토리얼 1차시태현 김
 
골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료욱진 양
 
Secrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modificationSecrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modificationHyuncheol Jeon
 
JSP 프로그래밍 #05 HTML과 JSP
JSP 프로그래밍 #05 HTML과 JSPJSP 프로그래밍 #05 HTML과 JSP
JSP 프로그래밍 #05 HTML과 JSPMyungjin Lee
 
JSP 프로그래밍 #03 서블릿
JSP 프로그래밍 #03 서블릿JSP 프로그래밍 #03 서블릿
JSP 프로그래밍 #03 서블릿Myungjin Lee
 
Progressive Web Apps
Progressive Web AppsProgressive Web Apps
Progressive Web Appsjungkees
 
비전공자의 자바스크립트 도전기
비전공자의 자바스크립트 도전기비전공자의 자바스크립트 도전기
비전공자의 자바스크립트 도전기jeong seok yang
 
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기NAVER Engineering
 
[115] clean fe development_윤지수
[115] clean fe development_윤지수[115] clean fe development_윤지수
[115] clean fe development_윤지수NAVER D2
 
진짜기초 Node.js
진짜기초 Node.js진짜기초 Node.js
진짜기초 Node.jsWoo Jin Kim
 
MongoDB 하루만에 끝내기
MongoDB 하루만에 끝내기MongoDB 하루만에 끝내기
MongoDB 하루만에 끝내기Seongkuk Park
 
React native 개발 및 javascript 기본
React native 개발 및 javascript 기본React native 개발 및 javascript 기본
React native 개발 및 javascript 기본Tj .
 
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 4. promise
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 4. promise[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 4. promise
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 4. promiseNAVER D2
 
ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!WooYoung Cho
 

What's hot (19)

[하코사세미나]미리보는 대규모 자바스크립트 어플리케이션 개발
[하코사세미나]미리보는 대규모 자바스크립트 어플리케이션 개발[하코사세미나]미리보는 대규모 자바스크립트 어플리케이션 개발
[하코사세미나]미리보는 대규모 자바스크립트 어플리케이션 개발
 
발렌타인 웨비너 7회 - React를 이용한 웹 앱 개발 살펴보기
발렌타인 웨비너 7회 - React를 이용한 웹 앱 개발 살펴보기발렌타인 웨비너 7회 - React를 이용한 웹 앱 개발 살펴보기
발렌타인 웨비너 7회 - React를 이용한 웹 앱 개발 살펴보기
 
ReactJS로 시작하는 멀티플랫폼 개발하기
ReactJS로 시작하는 멀티플랫폼 개발하기ReactJS로 시작하는 멀티플랫폼 개발하기
ReactJS로 시작하는 멀티플랫폼 개발하기
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JS
 
React 튜토리얼 1차시
React 튜토리얼 1차시React 튜토리얼 1차시
React 튜토리얼 1차시
 
골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료
 
Secrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modificationSecrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modification
 
JSP 프로그래밍 #05 HTML과 JSP
JSP 프로그래밍 #05 HTML과 JSPJSP 프로그래밍 #05 HTML과 JSP
JSP 프로그래밍 #05 HTML과 JSP
 
JSP 프로그래밍 #03 서블릿
JSP 프로그래밍 #03 서블릿JSP 프로그래밍 #03 서블릿
JSP 프로그래밍 #03 서블릿
 
Progressive Web Apps
Progressive Web AppsProgressive Web Apps
Progressive Web Apps
 
비전공자의 자바스크립트 도전기
비전공자의 자바스크립트 도전기비전공자의 자바스크립트 도전기
비전공자의 자바스크립트 도전기
 
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
 
Clojure Chapter.6
Clojure Chapter.6Clojure Chapter.6
Clojure Chapter.6
 
[115] clean fe development_윤지수
[115] clean fe development_윤지수[115] clean fe development_윤지수
[115] clean fe development_윤지수
 
진짜기초 Node.js
진짜기초 Node.js진짜기초 Node.js
진짜기초 Node.js
 
MongoDB 하루만에 끝내기
MongoDB 하루만에 끝내기MongoDB 하루만에 끝내기
MongoDB 하루만에 끝내기
 
React native 개발 및 javascript 기본
React native 개발 및 javascript 기본React native 개발 및 javascript 기본
React native 개발 및 javascript 기본
 
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 4. promise
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 4. promise[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 4. promise
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 4. promise
 
ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!
 

Viewers also liked

People's Insights Volume 1, Issue 22 : GetTaxi
People's Insights Volume 1, Issue 22 : GetTaxiPeople's Insights Volume 1, Issue 22 : GetTaxi
People's Insights Volume 1, Issue 22 : GetTaxiMSL
 
MeaNstack on Docker
MeaNstack on DockerMeaNstack on Docker
MeaNstack on DockerDaniel Ku
 
Getting Started with Redis
Getting Started with RedisGetting Started with Redis
Getting Started with RedisDaniel Ku
 
Google Analytics
Google AnalyticsGoogle Analytics
Google AnalyticsDaniel Ku
 
Deploying an application with Chef and Docker
Deploying an application with Chef and DockerDeploying an application with Chef and Docker
Deploying an application with Chef and DockerDaniel Ku
 
Object-oriented Javascript
Object-oriented JavascriptObject-oriented Javascript
Object-oriented JavascriptDaniel Ku
 
Indices APIs - Elasticsearch Reference
Indices APIs - Elasticsearch ReferenceIndices APIs - Elasticsearch Reference
Indices APIs - Elasticsearch ReferenceDaniel Ku
 
Beautiful code instead of callback hell using ES6 Generators, Koa, Bluebird (...
Beautiful code instead of callback hell using ES6 Generators, Koa, Bluebird (...Beautiful code instead of callback hell using ES6 Generators, Koa, Bluebird (...
Beautiful code instead of callback hell using ES6 Generators, Koa, Bluebird (...andreaslubbe
 
ECMAScript 6 and the Node Driver
ECMAScript 6 and the Node DriverECMAScript 6 and the Node Driver
ECMAScript 6 and the Node DriverMongoDB
 
Prepared your financial future with Stephen Cagnassola
Prepared your financial future with Stephen CagnassolaPrepared your financial future with Stephen Cagnassola
Prepared your financial future with Stephen CagnassolaStephen J. Cagnassola
 
Итоги работы Ошской межобластной клинической больницы в 2013 году
Итоги работы Ошской межобластной клинической больницы в 2013 годуИтоги работы Ошской межобластной клинической больницы в 2013 году
Итоги работы Ошской межобластной клинической больницы в 2013 годуVasilii Lotcev
 
InterTech is a leading hotel construction company in Russia
InterTech is a leading hotel construction company in RussiaInterTech is a leading hotel construction company in Russia
InterTech is a leading hotel construction company in RussiaMaxim Gavrik
 
природный парк
природный паркприродный парк
природный паркOlga Antropova
 
Sync async-blocking-nonblocking-io
Sync async-blocking-nonblocking-ioSync async-blocking-nonblocking-io
Sync async-blocking-nonblocking-ioCheoloh Bae
 
Redis for the Everyday Developer
Redis for the Everyday DeveloperRedis for the Everyday Developer
Redis for the Everyday DeveloperRoss Tuck
 

Viewers also liked (20)

Utilizing Bluebird Promises
Utilizing Bluebird PromisesUtilizing Bluebird Promises
Utilizing Bluebird Promises
 
People's Insights Volume 1, Issue 22 : GetTaxi
People's Insights Volume 1, Issue 22 : GetTaxiPeople's Insights Volume 1, Issue 22 : GetTaxi
People's Insights Volume 1, Issue 22 : GetTaxi
 
MeaNstack on Docker
MeaNstack on DockerMeaNstack on Docker
MeaNstack on Docker
 
Getting Started with Redis
Getting Started with RedisGetting Started with Redis
Getting Started with Redis
 
Google Analytics
Google AnalyticsGoogle Analytics
Google Analytics
 
Deploying an application with Chef and Docker
Deploying an application with Chef and DockerDeploying an application with Chef and Docker
Deploying an application with Chef and Docker
 
Object-oriented Javascript
Object-oriented JavascriptObject-oriented Javascript
Object-oriented Javascript
 
Indices APIs - Elasticsearch Reference
Indices APIs - Elasticsearch ReferenceIndices APIs - Elasticsearch Reference
Indices APIs - Elasticsearch Reference
 
Beautiful code instead of callback hell using ES6 Generators, Koa, Bluebird (...
Beautiful code instead of callback hell using ES6 Generators, Koa, Bluebird (...Beautiful code instead of callback hell using ES6 Generators, Koa, Bluebird (...
Beautiful code instead of callback hell using ES6 Generators, Koa, Bluebird (...
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
 
ECMAScript 6 and the Node Driver
ECMAScript 6 and the Node DriverECMAScript 6 and the Node Driver
ECMAScript 6 and the Node Driver
 
Prepared your financial future with Stephen Cagnassola
Prepared your financial future with Stephen CagnassolaPrepared your financial future with Stephen Cagnassola
Prepared your financial future with Stephen Cagnassola
 
Actividad artística
Actividad artística Actividad artística
Actividad artística
 
Итоги работы Ошской межобластной клинической больницы в 2013 году
Итоги работы Ошской межобластной клинической больницы в 2013 годуИтоги работы Ошской межобластной клинической больницы в 2013 году
Итоги работы Ошской межобластной клинической больницы в 2013 году
 
InterTech is a leading hotel construction company in Russia
InterTech is a leading hotel construction company in RussiaInterTech is a leading hotel construction company in Russia
InterTech is a leading hotel construction company in Russia
 
природный парк
природный паркприродный парк
природный парк
 
Castellano
CastellanoCastellano
Castellano
 
Sync async-blocking-nonblocking-io
Sync async-blocking-nonblocking-ioSync async-blocking-nonblocking-io
Sync async-blocking-nonblocking-io
 
зош №19
зош №19зош №19
зош №19
 
Redis for the Everyday Developer
Redis for the Everyday DeveloperRedis for the Everyday Developer
Redis for the Everyday Developer
 

Similar to Promise and Bluebird

[JS] Function.prototype.bind
[JS] Function.prototype.bind[JS] Function.prototype.bind
[JS] Function.prototype.bindJinhyuck Kim
 
Promise in javascript
Promise in javascriptPromise in javascript
Promise in javascriptnamwook lim
 
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍Young-Beom Rhee
 
Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저Circulus
 
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...Young-Beom Rhee
 
프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oopYoung-Beom Rhee
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기Heo Seungwook
 
EcmaScript6(2015) Overview
EcmaScript6(2015) OverviewEcmaScript6(2015) Overview
EcmaScript6(2015) Overviewyongwoo Jeon
 
Learning Node Book, Chapter 5
Learning Node Book, Chapter 5Learning Node Book, Chapter 5
Learning Node Book, Chapter 5Ji Hun Kim
 
C Language I
C Language IC Language I
C Language ISuho Kwon
 
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...탑크리에듀(구로디지털단지역3번출구 2분거리)
 
Angular2 가기전 Type script소개
 Angular2 가기전 Type script소개 Angular2 가기전 Type script소개
Angular2 가기전 Type script소개Dong Jun Kwon
 
자바스크립트 함수
자바스크립트 함수자바스크립트 함수
자바스크립트 함수유진 변
 

Similar to Promise and Bluebird (20)

[JS] Function.prototype.bind
[JS] Function.prototype.bind[JS] Function.prototype.bind
[JS] Function.prototype.bind
 
Promise in javascript
Promise in javascriptPromise in javascript
Promise in javascript
 
Redux
ReduxRedux
Redux
 
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
 
Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저
 
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
 
Spring Boot 2
Spring Boot 2Spring Boot 2
Spring Boot 2
 
프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop
 
함수적 사고 2장
함수적 사고 2장함수적 사고 2장
함수적 사고 2장
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 
EcmaScript6(2015) Overview
EcmaScript6(2015) OverviewEcmaScript6(2015) Overview
EcmaScript6(2015) Overview
 
Learning Node Book, Chapter 5
Learning Node Book, Chapter 5Learning Node Book, Chapter 5
Learning Node Book, Chapter 5
 
C Language I
C Language IC Language I
C Language I
 
Basic git-commands
Basic git-commandsBasic git-commands
Basic git-commands
 
Eclipse RCP 1/2
Eclipse RCP 1/2Eclipse RCP 1/2
Eclipse RCP 1/2
 
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
 
Angular2 가기전 Type script소개
 Angular2 가기전 Type script소개 Angular2 가기전 Type script소개
Angular2 가기전 Type script소개
 
자바스크립트 함수
자바스크립트 함수자바스크립트 함수
자바스크립트 함수
 
7장매크로
7장매크로7장매크로
7장매크로
 
자바스크립트 클래스의 프로토타입(prototype of class)
자바스크립트 클래스의  프로토타입(prototype of class)자바스크립트 클래스의  프로토타입(prototype of class)
자바스크립트 클래스의 프로토타입(prototype of class)
 

Recently uploaded

Merge (Kitworks Team Study 이성수 발표자료 240426)
Merge (Kitworks Team Study 이성수 발표자료 240426)Merge (Kitworks Team Study 이성수 발표자료 240426)
Merge (Kitworks Team Study 이성수 발표자료 240426)Wonjun Hwang
 
캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차캐드앤그래픽스
 
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...Kim Daeun
 
A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)Tae Young Lee
 
MOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution DetectionMOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution DetectionKim Daeun
 
Console API (Kitworks Team Study 백혜인 발표자료)
Console API (Kitworks Team Study 백혜인 발표자료)Console API (Kitworks Team Study 백혜인 발표자료)
Console API (Kitworks Team Study 백혜인 발표자료)Wonjun Hwang
 

Recently uploaded (6)

Merge (Kitworks Team Study 이성수 발표자료 240426)
Merge (Kitworks Team Study 이성수 발표자료 240426)Merge (Kitworks Team Study 이성수 발표자료 240426)
Merge (Kitworks Team Study 이성수 발표자료 240426)
 
캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차
 
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
 
A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)
 
MOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution DetectionMOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution Detection
 
Console API (Kitworks Team Study 백혜인 발표자료)
Console API (Kitworks Team Study 백혜인 발표자료)Console API (Kitworks Team Study 백혜인 발표자료)
Console API (Kitworks Team Study 백혜인 발표자료)
 

Promise and Bluebird

  • 1. Promise and Bluebird Daniel Ku (http://danielku.com/)
  • 2. PromiseJavascript 코드 가독성을 높이기 위한 위한 베스트 프랙티스 Promise 스펙: https://promisesaplus.com/
  • 3. Bluebird가장 유명한 Promise 구현체 중 하나 https://github.com/petkaantonov/bluebird
  • 4. Node.js 사용 시 이렇게 선언하게 한다. var Promise = require('bluebird'); 나는 보통 다음과 같이 선언한다. var Q = require('bluebird'); 이유: 짧으니까
  • 6. 이러한 코드가 있다고 하자. User.findOne({email: email}, function(err, user) { if (err) { console.error(err); } else { Group.find({owner: user.id}, function(err, groups) { if (err) { console.error(err); } else { try { // do something with groups console.log('success'); } catch (err) { console.error(err); } } }); });
  • 7. 문제점 1. 중첩된 콜백과 if절 등으로 가독성이 떨어진다. User.findOne({email: email}, function(err, user) { if (err) { console.error(err); } else { Group.find({owner: user.id}, function(err, groups) { if (err) { console.error(err); } else { try { // do something with groups console.log('success'); } catch (err) { console.error(err); } } }); });
  • 8. 문제점 2. 동일한 에러 처리 로직이 중복되어 사용되었다. User.findOne({email: email}, function(err, user) { if (err) { console.error(err); } else { Group.find({owner: user.id}, function(err, groups) { if (err) { console.error(err); } else { try { // do something with groups console.log('success'); } catch (err) { console.error(err); } } }); });
  • 9. Promise를 이용해 바꾸어 보자. 더 길어지긴 했지만, new Promise(function(resolve, reject) { User.findOne({email: email}, function(err, user) { if (err) reject(err); else resolve(user); }); }) .then(function(user) { return new Promise(function(resolve, reject) { Group.find({owner: user.id}, function(err, groups) { if (err) reject(err); else resolve(groups); }); }); }) .then(function(groups) { // do something with groups }) .then(function() { console.log('success'); }) .catch(function(err) { console.error(err); });
  • 10. 개선점 1. 작업의 단계가 명확히 구분된다. new Promise(function(resolve, reject) { User.findOne({email: email}, function(err, user) { if (err) reject(err); else resolve(user); }); }) .then(function(user) { return new Promise(function(resolve, reject) { Group.find({owner: user.id}, function(err, groups) { if (err) reject(err); else resolve(groups); }); }); }) .then(function(groups) { // do something with groups }) .then(function() { console.log('success'); }) .catch(function(err) { console.error(err); });
  • 11. 개선점 2. 에러도 한군데에서 다 처리한다. new Promise(function(resolve, reject) { User.findOne({email: email}, function(err, user) { if (err) reject(err); else resolve(user); }); }) .then(function(user) { return new Promise(function(resolve, reject) { Group.find({owner: user.id}, function(err, groups) { if (err) reject(err); else resolve(groups); }); }); }) .then(function(groups) { // do something with groups }) .then(function() { console.log('success'); }) .catch(function(err) { console.error(err); });
  • 12. 더 개선해 보자. 사용자를 찾는 부분을.. new Promise(function(resolve, reject) { User.findOne({email: email}, function(err, user) { if (err) reject(err); else resolve(user); }); });
  • 13. 다음과 같이 Wrapper 형태로 뽑아냈다고 가정해보자. var UserWrapper = { findOne: function(query) { return new Promise(function(resolve, reject) { User.findOne(query, function(err, user) { if (err) reject(err); else resolve(user); }); }); } };
  • 14. 그룹들을 찾는 부분도 마찬가지로.. var GroupWrapper = { find: function(query) { return new Promise(function(resolve, reject) { Group.find(query, function(err, groups) { if (err) reject(err); else resolve(groups); }); }); } };
  • 15. 그러면 이런 식으로 바꿀 수 있다. 가독성이 훨씬 좋아졌다. UserWrapper.findOne({ email: email }) .then(function(user) { return GroupWrapper.find({ owner: user.id }); }) .then(function(groups) { // do something with groups }) .then(function() { console.log('success'); }) .catch(function(err) { console.error(err); });
  • 16. 참고로 이러한 변환 과정을 Promisification이라고 하며, Bluebird에서 제공하는 Promise.promisify() 함수를 이용하면 더 쉽게 할 수 있다.
  • 17. 극단적으로는 다음과도 같이 할 수 있다. findUserByEmail(email) .then(findOwningGroups) .then(doSomethingWithGroups) .then(whenSuccess) .catch(whenFail); 주석이 필요없지 않은가? ㅋㅋ
  • 19. 시작: Promise Chain을 시작하는 방법 가장 쉬운 방법 중 하나는 Promise.defer() 함수를 이용하는 방 법이지만 deprecated되었다. function dont_do_like_this() { var deferred = Promise.defer(); doSomethingAsync(function(err, result) { if (err) return deferred.reject(err); deferred.resolve(result); }); return deferred.promise; }
  • 20. 그러므로 다음과 같이 Constructor를 이용하는 것이 더 바람직하 다. function ok() { return new Promise(function (resolve, reject) { doSomethingAsync(function(err, result) { if (err) return reject(err); resolve(result); }); }); }
  • 21. Callback이 없다면 Promise.try() 함수를 이용할 수도 있다. function checkSomething(something) { return Promise.try(function () { if (is_not_valid(something)) { throw new Error('Something is not valid.'); } return something; }); }
  • 22. 로직 없이 주어진 값이나 오브젝트로 바로 Promise를 생성할 수도 있다. function startWithValue(value) { return Promise.resolve(value); } 심지어 에러로 Promise를 생성할 수도 있다. 쓸 일이 있을까? function startWithError(error) { return Promise.reject(error); }
  • 23. 중간: Promise Chain을 연결시키는 방법 Promise는 다음과 같이 .then() 함수와 .catch() 함수로 이어 나갈 수 있다. ajaxGetAsync(url) .then(function(result) { return parseValueAsync(result); }) .catch(function(error) { console.error('error:', error); });
  • 24. 직전 Promise의 결과 값과 상관 없이 특정 값으로 Promise Chain을 이어가려면.. somethingAsync() .return(value); 위는 아래와 같다. somethingAsync() .then(function() { return value; });
  • 25. 직전 Promise의 결과 값과 상관 없이 특정 에러로 Promise Chain을 이어가려면.. somethingAsync() .throw(reason); 위는 아래와 같다. somethingAsync() .then(function() { throw reason; });
  • 26. .finally() 함수도 있다. Promise.resolve('test') .catch(console.error.bind(console)) .finally(function() { return 'finally'; }) .then(function(result) { console.log(result); // result is 'test' });
  • 27. 끝: Promise Chain을 끝내는 방법 가장 간단한 방법은 더 이상 Promise Chain을 연결하지 않는 것 이다.
  • 28. 하지만 명시적으로 .done() 함수를 쓸 수 있다. somethingAsync() .done();
  • 29. Alias Promise.try() === Promise.attemp() .catch() === .caught() .return() === .thenReturn() .throw() === .thenThrow() .finally() === .lastly()
  • 31. 이렇게 하지 않도록 주의하라. (X) somethingAsync() .then(function(result) { return anotherAsync(result); }, function(err) { handleError(err); });
  • 32. 이렇게 해야 한다. (O) somethingAsync() .then(function(result) { return anotherAsync(result); }) .catch(function(err) { handleError(err); });
  • 33. 이렇게 하지 않도록 주의하라. (X) var promise = somethingAsync(); if (is_another_necessary) { promise.then(function(result) { return anotherAsync(result); }); } promise.then(function(result) { doSomethingWithResult(result); });
  • 34. 이렇게 해야 한다. (O) var promise = somethingAsync(); if (is_another_necessary) { promise = promise.then(function(result) { return anotherAsync(result); }); } promise.then(function(result) { doSomethingWithResult(result); });
  • 41. 설명이 필요 없다. Group.listAsync({user: user.id}) .map(function(group) { return group.removeAsync(user.id); }) .then(function() { return user.removeAsync(); });
  • 42. 설명이 필요 없다. Group.listAsync({user: user.id}) .filter(function(group) { return group.owner_id === user.id; });
  • 43. .map() 혹은 .filter()에서의 concurrency 제한에 대하여 Group.listAsync({user: user.id}) .map(function(group) { return group.removeAsync(user.id); }, {concurrency: 1});
  • 44. 참고로 하나씩 처리하려면 이렇게 할 수도 있다. Group.listAsync({user: user.id}) .reduce(function(promise, group) { return promise.then(function(groups) { return group.removeAsync(user.id) .then(function(group) { groups.push(group); }) .return(groups); }); }, []); (확인은 안 해봤지만 아마도 틀리지 않을 듯;;)
  • 46. 설명이 필요 없다. Promise .delay(500) .then(function() { return 'Hello world'; }) .delay(500) .then(function(result) { console.log(result); });
  • 48. Promise Chain을 연결하긴 하지만 결과를 넘겨주진 않음.. somethingAsync() .tap(function(result_of_somethingAsync) { return anotherAsync(result_of_somethingAsync); }) .then(function(result_of_somethingAsync) { console.log(result_of_somethingAsync); });
  • 50. 이런 식으로 앞의 결과를 나중에 써야할 경우엔 콜백에서처럼 가독 성이 떨어지는데.. somethingAsync() .spread(function (a, b) { return anotherAsync(a, b) .then(function (c) { return a + b + c; }); });
  • 51. 이런 식으로도 해결할 수 있지만.. var scope = {}; somethingAsync() .spread(function (a, b) { scope.a = a; scope.b = b; return anotherAsync(a, b); }) .then(function (c) { return scope.a + scope.b + c; });
  • 52. 이게 더 깔끔하다. somethingAsync() .bind({}) .spread(function (a, b) { this.a = a; this.b = b; return anotherAsync(a, b); }) .then(function (c) { return this.a + this.b + c; });
  • 54. 10초 마다 어떤 작업을 반복하도록 하려면?
  • 55. 10초 마다 어떤 작업을 반복하도록 하려면? var loop = function() { Worker.executeAsync() .catch(function(err) { console.error('err:', err); }) .delay(10000) .then(loop); }; loop();
  • 56. 매우 긴 작업 목록을 10개씩 끊어서 처리하려면?
  • 57. 매우 긴 작업 목록을 10개씩 끊어서 처리하려면? var traverseJobs = function(handleTenJobsAsync) { var limit = 10; var loop = function(skip) { return listJobsAsync(limit, skip) .then(function(jobs) { if (jobs.length) { return handleTenJobsAsync(jobs) .then(function() { return loop(skip + limit); }); } }); }; return loop(0); };
  • 59. — Resource Management — Cancellation & .timeout() — Built-in Errors — Error Management configuration — Generators https://github.com/petkaantonov/bluebird/blob/ master/API.md
  • 60. 참고 — Bluebird — Bluebird API Reference — Promise Anti-patterns