이전 포스팅 참고
- Lodash 의 지연 평가와 비교
지연 평가는 Partial.js 만 지원하는게 아닙니다. 마찬가지로 지연 평가를 지원하는 Lodash 와 비교를 해보도록 하겠습니다.
const _ = require('lodash');
const list = _.range(10000);
const limit = 100;
const square = v => v * v;
const odd = v => !!(v % 2);
console.time();
for (let i = 0 ; i < 10000 ; i++) {
_(list).map(square).filter(odd).take(limit).value();
}
console.timeEnd();
Lodash 의 지연 평가는 값을 wrapping 한 후 함수들을 등록하면, 함수 실행을 지연 시켰다가 이후 value() 함수 호출 시 wrapping 을 풀면서 평가하는 방식입니다. 위 코드의 경우 평균 80 ~ 90ms 의 결과를 보였습니다.
const _ = require('partial-js');
const list = _.range(10000);
const limit = 100;
const square = v => v * v;
const odd = v => !!(v % 2);
console.time();
for (let i = 0 ; i < 10000 ; i++) {
_.go(list, L.map(square), L.filter(odd), L.take(limit));
}
console.timeEnd();
동일한 처리를 Partial.js 로 작성한 위 코드는 평균 50 ~ 60ms 의 결과를 보였습니다.
단순 비교해봐도, Partial.js 의 성능이 Lodash 에 비해 1.5 배 정도 좋은 성능을 보이고 있습니다.
지연 평가를 지원하는 라이브러리는 이 외에도 Lazy.js / Ramda.js / Fx.js 등이 있습니다.
포스팅을 하면서 Partial.js 위주로 얘기를 하고 있지만, 각 라이브러리 간 성능 비교를 통해 사용할 라이브러리를 결정하는게 좋아보입니다.
- 동적 지연 평가
Partial.js 의 지연 평가는 개발자가 L 을 통해 명시적으로 지연 평가 여부를 결정하므로, 반자동 지연 평가 입니다.
지연 평가를 할 것인지 직접 정하는 것은 개발자에 따라 장점일 수도 있고, 단점일 수도 있을 것 같습니다.
하지만 Partial.js 에는 지연 평가를 동적으로 할 수 있도록 별도의 함수를 지원하고 있습니다.
그전에 지원하는 함수를 쓰지 않고 지연 평가를 분기 처리해보도록 하겠습니다.
const _ = require('partial-js');
let count = 0;
const square = v => {
count += 1;
console.info(count);
return v * v;
};
const odd = v => !!(v % 2);
const test1 = __(
_.range,
_.if(list => list.length < 100, __(
_.map(square),
_.filter(odd),
_.take(10)
)).else(__(
L.map(square),
L.filter(odd),
L.take(10)
)),
console.info);
test1(50);
// 1 ~ 50 (count - 50번 반복)
// [1, 9, 25, 49, 81, 121, 169, 225, 289, 361]
test1(100);
// 1 ~ 20 (count - 20번 반복)
// [1, 9, 25, 49, 81, 121, 169, 225, 289, 361]
위 코드에서 __ 는 Partial.js 의 _.pipe 입니다. _.if 를 활용해 list 의 길이가 100 보다 작은 경우엔 엄격한 평가를 수행하고, 100 이상인 경우엔 지연 평가를 하는 코드입니다. 실제로 square 를 얼마나 호출하는지 확인해보기 위해 count 를 찍었고, 배열의 길이가 50인 경우엔 엄격한 평가를 수행해 50번 반복한 반면 길이 100의 경우 지연 평가를 통해 20번 반복만 수행한 것을 확인할 수 있습니다.
위와 같은 코드는 확실히 지연 평가를 동적으로 수행할 수 있지만, L 을 활용한 코드와 _ 를 활용한 코드 두 가지를 모두 작성해야 하는 번거로움이 있습니다. 이를 해결하기 위한 함수가 L.strict 입니다.
const _ = require('partial-js');
let count = 0;
const square = v => {
count += 1;
console.info(count);
return v * v;
};
const odd = v => !!(v % 2);
const test1 = __(
_.range,
L.strict(list => list.length < 100),
L.map(square),
L.filter(odd),
L.take(10),
console.info)
);
test1(50);
// 1 ~ 50
// [1, 9, 25, 49, 81, 121, 169, 225, 289, 361]
test1(100);
// 1 ~ 20
// [1, 9, 25, 49, 81, 121, 169, 225, 289, 361]
Partial.js 의 L 의 동작은 아래와 같습니다.
1. L 을 통해 명시적으로 지연 평가를 만들면 무조건 지연 평가로 동작합니다.
2. L.strict 에 함수를 넣어 그 결과가 true 를 반환하면, 만들어 둔 지연 평가와 매칭 되는 엄격한 평가로 대체해 동작합니다.
3. L.strict 를 사용하지 않으면 항상 지연 평가입니다.
따라서 L.strict 를 통해 작성한 코드 또한 이전 코드와 동일하게 배열 길이 100 을 기준으로 엄격한 평가와 지연 평가 수행이 나뉩니다.
위 코드를 L.strict 에 숨겨진 기능으로 조금 더 축약할 수 있습니다.
L.strict(100) === L.strict(list => list.length < 100)
L.strict 에 함수 대신 숫자를 넘기면 자동으로 위와 같이 동작합니다.
이는 편한 기능 같기도 하지만, 오히려 코드 가독성을 해칠 수 있을 것 같으니 실무에서 사용한다면 팀 내에서 충분히 논의가 필요할 것 같습니다. (별거 아닌 것 같아도 이런 부분에서 의외로 개발자들간의 의견이 갈리더라구요)
위에서 언급한 것 처럼 지연 평가를 지원하는 자바스크립트 라이브러리는 Partial.js 외에도 여러가지가 있습니다.
Partial.js 를 중점으로 다루고 있지만, 이러한 개념은 다른 라이브러리에서도 동일할 것 입니다.
함수형 스타일 및 지연 평가를 적극 사용할 예정이라면 충분한 비교 평가를 통해 라이브러리를 정한 후 프로젝트를 시작하시기 바랍니다.
'Backend > 함수형 자바스크립트' 카테고리의 다른 글
기본 객체 다루기 (0) | 2021.11.13 |
---|---|
값 다루기 (0) | 2021.11.06 |
지연 평가 (2) (0) | 2021.10.23 |
지연 평가 (1) (0) | 2021.10.17 |
Partial.js (3) (0) | 2021.10.09 |