허구헌날 개발하는데 써먹는 생태계 풍부한 라이브러리/프레임워크들도 물론 나쁠 건 없고, 결국 실제 개발을 진행할 때는 이것들을 써야할 테지만.
가끔 여기저기 개발 관련 뉴스를 서핑하다보면 흥미롭게 느껴지는 신상(?) 라이브러리를 발견하고는 하는데, 이런 걸 그냥 눈으로만 대충 훑고 지나가는게 항상 조금 아쉽게 느껴졌다.
개인적으로 이들 신선한 아이디어를 직접 써먹다보면 나 자신에게도 나름 인사이트가 생기지 않을지 싶어, 블로그에다가 간간히 기록을 남겨두려 한다.
아무튼, 오늘은 최근 눈팅하다가 ForesightJS라는 자바스크립트 라이브러리가 조금 흥미롭게 다가왔던지라. 그것을 탐방(?)해볼 생각이다.

ForesightJS 라이브러리는 사용자의 의도를 미리 예측해 그에 따라 렌더링을 하도록 도와주는 라이브러리다.
이렇게 말로 떠드는 것보다 이미지로 보는 게 훨씬 이해가 빠를 텐데, 보다시피 원래라면 마우스가 엘리먼트에 올라갈 때 렌더링이 이뤄지며 색상 및 텍스트가 바뀔 걸 마우스 궤도를 예측하여 미리 렌더링을 실행한다.
기본적으로 마우스 궤적 예측 분석 / 키보드 네비게이션 예측 분석 / 스크롤 예측 분석 세 가지를 모니터링하도록 서포트하고, 이를 통해 사용자가 예측 전략을 작성해 고객에게 최적화된 성능을 제공하도록 하는 라이브러리라고 한다.
한 번 리액트 프로젝트를 만들어 위 샘플과 똑같은 상황을 똑같이 구현해보겠다.
npm을 사용하면 npm install js.foresight로, yarn을 사용하면 yarn add js.foresight로 라이브러리 설치가 가능하다.
# npm 설치
npm install js.foresight
# yarn 설치
yarn add js.foresight
그냥 테스트용 프로젝트라 대충 마우스 호버시 색깔이 빨간색으로 변하는 div를 하나 만들어줌.
const HoverRedDiv = () => {
const [isHovered, setIsHovered] = useState(false);
const handleMouseEnter = () => {
setIsHovered(true);
};
const handleMouseLeave = () => {
setIsHovered(false);
};
const divStyle = {
width: '75px',
height: '75px',
backgroundColor: isHovered ? 'red' : '#f0f0f0',
color: isHovered ? 'white' : 'black',
border: '2px solid #ccc',
borderRadius: '10px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
transition: 'background-color 0.3s ease',
fontSize: '18px',
fontWeight: 'bold',
margin: '10px',
};
return (
<div
style={divStyle}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>호버
</div>
);
};
export default HoverRedDiv;
그리고 HoverRedDiv를 5*5 대형으로 배치했다.
import './App.css';
import HoverRedDiv from './component/HoverRedDiv';
function App() {
const appStyle = {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '20px'
};
const rowStyle = {
display: 'flex'
};
return (
<div style={appStyle}>
{Array.from({ length: 5 }, (_, rowIndex) => (
<div key={rowIndex} style={rowStyle}>
{Array.from({ length: 5 }, (_, colIndex) => (
<HoverRedDiv key={`${rowIndex}-${colIndex}`} />
))}
</div>
))}
</div>
);
}
export default App;

이렇게 만들면 그냥 단순히 마우스가 호버될 때 div 색상이 빨간색으로 바뀌고, 아웃될 때 다시 색상이 회색으로 돌아온다.
이제 한 번 설치한 ForesightJS를 도입해 Prefetch 렌더링을 도입해보자.
function App() {
ForesightManager.initialize({
// 마우스 예측 설정
enableMousePrediction: true, // 마우스 궤적 예측 활성화/비활성화
trajectoryPredictionTime: 150, // 예측할 시간 범위 (10-200ms)
positionHistorySize: 8, // 추적할 마우스 위치 개수 (2-30)
// 키보드 예측 설정
enableTabPrediction: true, // 키보드 탐색 예측 활성화/비활성화
tabOffset: 2, // 트리거할 탭 스톱 수 (0-20)
// 스크롤 예측 설정
enableScrollPrediction: true, // 스크롤 예측 활성화/비활성화
scrollMargin: 150, // 스크롤 감지를 위한 픽셀 거리 (30-300)
// 터치 디바이스 설정
touchDeviceStrategy: "viewport", // "none", "viewport", "onTouchStart" 중 선택
// 연결 설정
minimumConnectionType: "3g", // "slow-2g", "2g", "3g", "4g" 중 선택
// 기본 요소 설정
defaultHitSlop: 0, // 모든 요소의 기본 히트 슬롭 (숫자 또는 {top, right, bottom, left})
})
...
그냥 테스트용이니깐. App 컴포넌트에서 ForesightManager.initialize를 등록해줬다. 주석 번역은 여기서 중요한 건 아니라 그냥 번역기 돌림.
import { useRef, useEffect } from "react"
import {
ForesightManager,
} from "js.foresight"
export default function useForesight(options) {
const elementRef = useRef(null)
const registerResults = useRef(null)
useEffect(() => {
if (!elementRef.current) return
registerResults.current = ForesightManager.instance.register({
element: elementRef.current,
...options,
})
}, [options])
return { elementRef, registerResults }
}
ForesightJS의 도큐먼트를 확인해보니 리액트 환경에서는 useForesight라는 훅을 사용자가 직접 만들어 이 훅을 사용해서 동작을 구현해야 한다고 작성되어 있다.
보통 이런 건 라이브러리 개발진이 리액트용 플러그인으로 만들어 컴포넌트로 제공해주지 않나? 하는 생각이 들었지만... 만들어진지 얼마 되지 않은 라이브러리니 그러려니 하는 걸로.
const { elementRef, registerResults } = useForesight({
callback: () => {
handleMouseEnter(); // 예측 반경에 들어올 때 이 callback 이벤트가 발생한다.
},
hitSlop: 10,
name: "my-button",
})
return (
<div
style={divStyle}
// onMouseEnter={handleMouseEnter}
// onMouseLeave={handleMouseLeave}
ref={elementRef}
>호버
</div>
);
앞서 생성한 HoverRedDiv에서 MouseEnter, MouseLeave 이벤트를 제거하고, useForesight 훅을 가져와 ref로 넣어줬다. ForesightJS는 기본적으로 이벤트 기반으로 동작하는데, 위 예시로 들자면 HoverRedDiv가 ForesightJS가 모니터링하는 예측 반경에 들어왔을 때 등록한 callback 이벤트가 발생하는 식이다. 내가 원하는 건 색상을 빨간색으로 변경하는 동작인지라, 해당 callback 이벤트에서 handleMouseEnter() 이벤트를 실행하도록 처리해줬다.

여기까지 작성하고 실행해보면 마우스가 실제로 엘리먼트에 가닿기 전에 ForesightJS가 마우스 동작을 모니터링하여 렌더링 동작을 먼저 실행하는 걸 확인할 수 있다.
뭐, 여기까지 써보고 나서 느끼는 건... 흥미롭긴 한데 이게 실효성이 있는지는 잘 모르겠다. 인터넷 쇼핑몰에서처럼 스크롤을 내릴 때 상품 이미지를 여러개 렌더링해야 되서 속도가 느려질 수 있으니, 스크롤을 실제로 내리기 전 미리 prefetch를 실행하는데 써먹는 정도?
마우스 호버나 키보드의 경우는 페이지 렌더링 성능이 심히 떨어질 수 밖에 없는 특수한 경우가 아니라면 굳이 이것을 쓸 일이 없을 것 같은데, 그러한 페이지가 있다고 한들 그 페이지의 렌더링 성능이 1년 365일 항상 그렇게 떨어질 것 같지는 않다.
렌더링이 버벅이는 케이스가 아니라면, 구태여 prefetch를 도입할 이유가 없지 않을까? 오히려 (옵션으로 조절할 수 있기는 하지만) 마치 마우스 감도가 올라간 것 마냥 너무 빨리 실행되는 느낌이라 되려 어색한 감이 없잖아 있고.
그렇다면 ForesightJS가 항상 모니터링하는 건 아니고, 대용량 데이터 등으로 인해 렌더링이 저하된다던지 하는 경우에만 뭔가 동적으로 모니터링을 수행하도록 할 필요가 있는 것 같은데 그런 기능을 이 라이브러리가 제공하는지는 잘 모르겠다.
그리고 예측 반경에 들어올 때 실행되는 callback 이벤트가 있다면, 예측 반경에서 아웃될 때 실행되는 이벤트도 따로 있어야 하지 않은지 싶었다.