함수형 자바스크립트를 더 많은 영역에서 사용하기 위해 기능을 확장한 Partial.js 에 대해 더 알아보고자 합니다.
이미 이전 포스팅에서 Partial.js 의 _.pipe, _.go 함수에 대해선 어느정도 맛을 보았습니다.
_.pipe 는 실행 준비가 된 함수를 반환하는 파이프라인 함수고, _.go 는 즉시 실행하는 파이프라인 함수입니다.
_.go 를 사용할 때 2개 이상의 인자를 넘기기 위해선 _.mr 을 사용하는 것도 봤었습니다.
이번엔 좀 더 다른 예시들을 볼까 합니다.
- 함수를 리턴하는 함수와의 조합
const _ = require('partial-js');
const products = [
{ id: 1, price: 10000, isDiscount: true },
{ id: 2, price: 8000, isDiscount: false },
{ id: 3, price: 23000, isDiscount: true },
{ id: 4, price: 9500, isDiscount: true },
{ id: 5, price: 7000, isDiscount: false },
];
const id = _.go(products,
_.filter(item => item.isDiscount),
_.sortBy('price'),
_.first,
_.val('id'));
console.info(id); // 4
위 코드는 함수를 리턴하는 _.filter, _.sortBy 등의 함수를 _.go 와 조합해서 사용한 코드입니다.
위에서부터 순서대로 읽으면 상품 중에 할인중인 상품만 남긴 후 가격으로 정렬해 첫 번째 아이템의 id 를 확인합니다.
화살표함수와 함께 이런 형태로 작성한 코드는 가독성도 좋고 변경이 용이합니다.
- _.go 의 비동기 제어
_.go 는 함수적으로 비동기를 제어합니다. 내부적으로 함수들을 순차적으로 실행해 나가면서 비동기 함수의 결과를 재귀 함수로 꺼낸 후
다음 함수에게 이어주는 식으로 비동기 상황을 제어합니다.
Promise 의 경우 함수를 실행하면 { then: ... } 을 반환하므로 다른 동기 함수들과 중첩 사용을 할 수 없습니다.
_.go 의 경우엔 비동기 상황이 없을 경우 결과를 즉시 반환하므로 연속적으로 실행되는 함수들이 반드시 비동기일 필요는 없습니다.
따라서 _.go 는 비동기와 동기 함수들간의 조합성도 좋습니다.
_.go 함수가 callback 패턴의 함수와 조합되었을 때의 예시를 먼저 보겠습니다.
const _ = require('partial-js');
_.go(50,
_.callback((x, next) => {
setTimeout(() => {
next(x * 10);
}, 100);
}),
console.info); // 500
여기서 사용된 _.callback 함수는 내부적으로 비동기를 제어하는 파이프라인으로 변할 수 있도록 해주는 함수입니다.
첫 번째 함수를 실행하면서 내부적으로 만들어진 next 에 의해 전달된 결과는 다음 함수의 인자로 넘어갔습니다.
따라서 500 이라는 결과값이 출력되었네요.
const _ = require('partial-js');
const add = _.callback((a, b, next) => {
setTimeout(() => {
next(a + b);
}, 100);
});
const sub = _.callback((a, b, next) => {
setTimeout(() => {
next(a - b);
}, 100);
});
const mul = _.callback((a, b, next) => {
setTimeout(() => {
next(a * b);
}, 100);
});
_.go(_.mr(50, 10),
add,
result => sub(result, 20),
result => mul(result, 30),
console.info); // 1200
이번엔 _.callback 으로 지정한 여러개의 함수와 조합한 예시입니다.
이렇게 _.callback 을 사용해 미리 정의해 둔 add, sub 과 같은 함수는 실행하면 Promise 객체를 반환합니다. (설령 Promise 가 지원되지 않는 환경이라도 Partial.js 는 그 내부에 구현된 Promise 객체를 사용합니다)
_.go 는 이러한 Promise 를 받으면 내부적으로 재귀를 돌며 비동기 함수의 결과를 기다렸다가 다음 함수들을 순차적으로 실행합니다.
const _ = require('partial-js');
const Redis = require('ioredis');
const client = new Redis();
_.go('test-key',
(key) => client.get(key),
console.info); // 10
이번엔 _.callback 을 사용하지 않고 Promise 를 반환하는 함수와 _.go 함수를 조합해봤습니다.
미리 로컬 레디스에 test-key 라는 키에 10 이라는 value 를 세팅했고, client.get 은 Promise<string> 을 반환합니다.
_.callback 으로 Promise 객체를 반환하도록 만들지 않는 케이스에서도 잘 동작함을 확인할 수 있습니다.
- _.stop
일반 함수에서는 함수 중간 어디에서든 return 문을 사용해 함수를 빠져 나올 수 있습니다. (early return)
파이프라인에서도 early return 이 가능한데, _.stop 함수를 사용하면 됩니다. 간단한 예시를 보겠습니다.
const _ = require('partial-js');
_.go(null,
() => console.info(1),
() => console.info(3),
() => console.info(5),
_.stop,
() => console.info(7),
() => console.info(9));
// 1
// 3
// 5
이는 실행되는 파이프라인을 중간에 빠져나온 것이고, 파이프라인을 빠져나오면서 결과값도 같이 전달하고 싶다면 _.stop 함수에 그 값을 전달하면 됩니다.
const _ = require('partial-js');
const add = (a, b) => a + b;
const x = _.go(10,
result => add(result, 20),
result => add(result, 30),
result => add(result, 40),
result => _.stop(result),
result => add(result, 50),
result => add(result, 60));
console.info(x); // 100
이번에도 알 수 있는 _.go 와 _.pipe 의 장점은 잘게 쪼개놓으면 비동기 제어에 대한 준비도 이미 되어 있다는 것입니다.
이러한 특성 때문에 동기, 비동기 코딩을 동일한 스타일로 작성할 수 있습니다.
물론 실무에서 좀 더 활용해봐야겠지만, 비동기에 대한 특별한 처리가 필요없다는 점은 꽤 흥미롭게 느껴집니다.
다음 포스팅에서 Partial.js 의 비동기 제어에 대해 좀 더 알아보도록 하겠습니다.
'Backend > 함수형 자바스크립트' 카테고리의 다른 글
Partial.js (3) (0) | 2021.10.09 |
---|---|
Partial.js (2) (0) | 2021.10.02 |
함수 조립 (2) (0) | 2021.09.18 |
함수 조립 (1) (0) | 2021.09.11 |
Underscore.js - _.reduce (0) | 2021.09.05 |