2. Problem
● 반복되는 콜백 함수
async.waterfall([
// ...
function(callback) {
Model.Users.findUserByEmailAndPassword(username, password).then(function(user) {
callback(null, user);
}).catch(function(err) {
callback(err);
});
},
function(user, callback) {
Model.UserPermission.findByUserId(user.id).then(function(perms) {
user.perms = perms;
callback(null, user);
}).catch(function(err) {
callback(err);
})
}
], function(err, result) {
///
});
개발자가 지양해야 하는
것 중 가장 큰 하나는 중복
코드를 양산하는 것이다
3. 그럼 어떻게 해야 할까요?
● 흔히 생각할 수 있는 방법은? 공통함수화!
function(err) {
callback(err);
}
이 녀석을 공통 함수화시키면 될 것 같다!
문제는?? callback 변수가 async package 내부에서
정의하는 것이라 외부에서는 저것을 정의할 수 없다.
6. How to implement reusable callback functions
var callback = function(x1, y1, result) {
// do something with x1 and y1
};
function(...) {
// closure vars x1, y1
// option 1: make your own partial function
foo.bar( function(result) { return callback(x1, y1, result); });
// with ES6: foo.bar( (result) => callback(x1, y1, result); });
// option 2: use Function.bind
foo.bar( callback.bind(this, x1, y1); );
}
???
7. Function.prototype.bind()
● fun.bind(thisArg[, arg1[, arg2[, ...]]])
○ 특정 context에 한정된 새로운 함수를 만드는 함수
○ thisArg: 한정시킬 context
○ arg: fun을 호출할 때 앞에 붙일 arguments
● 사용처
○ Callback 함수 등에서 현재 context를 사용하고 싶을 때
○ Partially applied function 을 만들고 싶을 때
○ 특정 context를 미리 갖는 생성자를 만들고 싶을 때
○ 특정 함수를 호출하는 shortcut을 만들고 싶을 때
참고: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
8. How to implement reusable callback functions
var callback = function(x1, y1, result) {
// do something with x1 and y1
};
function(...) {
// closure vars x1, y1
// option 1: make your own partial function
foo.bar( function(result) { return callback(x1, y1, result); });
// with ES6: foo.bar( (result) => callback(x1, y1, result); });
// option 2: use Function.bind
foo.bar( callback.bind(this, x1, y1); );
} callback 이라는 함수를 현재 context에 bound 되고 x1,
y1을 앞에 미리 적용시킨 함수를 만들어서 callback으로
전달한다
9. Solution
var dbFailureHandler = function(msg, callback, err) {
log.error(msg, err);
callback(err);
};
async.waterfall([
// 사용자 탐색
function(callback) {
Model.Users.findUserByEmailAndPassword(username, password).then(function(user) {
callback(null, user);
}).catch(dbFailureHandler.bind(this, 'Fail to find user due to DB operation!', callback));
},
function(user, callback) {
Model.UserPermission.findByUserId(user.id).then(function(perms) {
user.perms = perms;
callback(null, user);
}).catch(dbFailureHandler.bind(this, 'Fail to find user permission due to DB operation!', callback));
}],
// callback
}