old : function(param1, param2){...} new : (param1, param2) ⇒ {...}
// old
const myFunc1 = function(name, age){
...
return ...
};
const result_old = myFunc1('crocoLee', 25);
// new
const myFunc2 = (name, age) => {
...
return ...
};
const result_new = myFunc2('crocoLee', 25);
// old
const word1 = 'father';
console.log('i am your', word1);
// new
const word1 = 'mother';
console.log(`i am your ${word1}`);
//결과1 : i am your father
//결과2 : i am your mother
Wrapper
wrapper는 함수(function)을 감싸 함수, 그리고 그 함수가 호출하는 하위함수들에서 발생하는 에러들의 처리를 담당한다.
prototype
javascript는 프로토타입 기반 언어이다. JAVA에서 인터페이스, 템플릿의 개념과 비슷하며 자바스크립트 내 모든 객체(인스턴스)는 프로토타입을 가진다. 모든 프로토타입의 디폴트 최상위 프로토타입은 Object()이며 Error()등의 내장 프로토타입이 존재한다. 커스텀으로 생성하는 것도 역시 가능하다. 인스턴스의 프로토타입을 알고자 할 때
const proto = Object.getProtoTypeOf(instance);
console.log(proto);
Object프로토타입의 getProtoTypeOf매서드를 사용하면 된다. 자바의 클래스 매서드와 매우 비슷한(?) 개념인 것 같다.
es6이상에선 파라미터로 오직 Object만이 강제되며, es5에선 파라미터에 오브젝트 이외값을 넣을 시 에러가 발생한다.
// Person 프로토타입(Object프로토타입 상속)
function Person(name, age, height) {
this.name = name;
this.age = age;
this.height = height;
};
const errors = new Error();
const person = new Person('Lee', 25, 177);
const protoPerson = Object.getPrototypeOf(person);
const protoErrors = Object.getPrototypeOf(errors);
console.log(`person1's prototype : ${protoPerson}`);
console.log(`errors' prototype : ${protoErrors}`);
wrapper.js : 에러처리를 전담함
errors : 에러 생성자들이 정의되어 있음
router : router가 정의되어 있음
api : Controller함수가 정의되어 있음
service : Service함수가 정의되어 있음
wrapper.js
/*
에러의 처리를 에러의 프로토타입의 생성자 이름이 errorConstructor인 경우와 Error가 배열인스턴스인 경우
와 그 외의 경우로 나눈다.
*/
const checkInternalError = function checkInternalError(err, next){
if (Array.isArray(err)) return next(err); // error 가 배열일 시 next로 에러를 넘기고
const proto = Object.getPrototypeOf(err); // error의 프로토타입이 객체인 경우
// 그 중 프로토타입 생성자의 이름이 errorConstructor이라면
if (proto && proto.constructor && proto.constructor.name === 'errorConstructor') return next(err);
// errors파일에 정의된 InternalError생성자를 이용해 에러객체(인스턴스)를 생성하여 반환하라
return ([new errors.InternalError(err, next), err]);
};
// 함수 내의 함수 구조 (params) => {(params) => {}}
/*
fn(함수)를 인자로 가지며 해당함수의 예외를 위에 정의된 checkInternalError를 이용해
수행하는 asyncWrapper를 정의한다
*/
exports.asyncWrapper = (fn) => async(req,res, next) => {
try {
await fn(req, res);
} catch(e) {
return checkInternalError(e, next);
}
};
함수 자체를 exports할 수는 없어 이 땐 변수에 할당해 주어야 한다.
// 불가능
exports.function(...){...}
// 가능
exports.myFunc = function(...){...};
error처리 과정 모식도
파일이 router ← api ← service 구조로 되어 있을 때.
errors.js
const errorTable = {
InvalidInputError: 400, // error 생성자명: 에러코드(상태코드)
AlreadyExistError: 400,
....
....
NotFound: 404,
RedisError: 500,
....
};
module.exports = errorTable;
service.js
exports.myFunc = async function myFuncService(...) {
...
// erros 파일의 errorTable에 정의된 에러 생성자를 중 하나를 이용해 에러 객체를 생성한 후 호출매서드에 던진다.
if (... ? > = ,,,) throw new errors.InvalidInputError();
...
}
api.js
const service = require('dir of service.js file');
exports.myFunc = async function myFunccontroller(req, res) {
....
const result = await service.myFunc(...);
....
return result;
};
// service매서드 호출함수에서 별다른 처리가 없기 때문에 api함수 호출매서드로 처리를 2차로 넘긴다.
router.js
// ----생략
const { asyncWrapper }= require('dir where function asyncWrapper belongs');
const api = require('dir of api.js file');
// 배열 = 배열
// api.myFunc로부터 2차로 넘어온 에러가 asyncWrapper에 의해 처리된다.
/* 경우의수
1. 에러가 배열인경우
2. 에러가 객체인 경우
3. 에러가 그 외의 경우 (InternalError)
*/
router.get('__dir', asyncWrapper(api.myFunc));
// 생략----
배열 = 배열
const normalArray = {lee, kim, jeong, han};
const {a , b, c, d} = normalArray;
console.log(a) // lee
console.log(b) // kim
console.log(c) // jeong
console.log(d) // han
주석 내용 풀이
예외) errors.js 파일에 별도 생성자 정의하지 않은 에러 발생 하더라도 하위 파일에선 따로 에러처리 구문이 삽입하지 않았기 때문에 asyncWrapper 까지 반드시 에러가 전달되어 모든 에러는 이 래퍼에서 처리되게 되는것입니다!! wow!