# 점진적 계산

## Content

SpreadJS는 [Workbook](/spreadjs/api/v19/classes/GC.Spread.Sheets.Workbook) 클래스의 `incrementalCalculation` 옵션을 `true`로 설정하여 실행 중 전체 계산을 여러 세그먼트로 나누는 점진적 계산을 지원합니다. 이 기능을 통해 계산 작업이 매우 클 경우에도 사용자 작업에 대한 응답성을 유지할 수 있습니다.
셀을 점진적으로 계산하고 UI 이벤트에 반응할 수 있습니다. 이 기능은 통합 문서에 많은 수식이 포함되어 있을 때 UI가 멈추는 것을 방지합니다. 계산 대기 중인 셀이 있는 동안 셀이 업데이트되면, 해당 업데이트된 셀과 그에 의존하는 셀이 계산 작업에 추가됩니다. 그러나 행/열 또는 시트를 삽입하거나 삭제하는 경우에는 대기 중인 계산이 취소되며, 이후 계산은 조정된 수식을 기준으로 수행됩니다.
`incrementalCalculation` 옵션을 `true`로 설정하면, `CalculationProgress` 이벤트를 사용하여 진행 상황을 추적할 수 있습니다.
다음 코드 샘플은 `CalculationProgress` 이벤트에서 진행 상황을 추적하는 방법을 보여줍니다:

```javascript
// 이 예제는 CalculationProgress 이벤트를 사용하여 계산 진행 상황을 로그로 출력합니다.
spread.options.incrementalCalculation = true;
spread.bind(GC.Spread.Sheets.Events.CalculationProgress, function (e, info) { 
    var msg = "Calculate "; 
    if (info.pendingCells === 0) { 
        msg += "finished"; 
    } else if (info.iterate >= 0) { 
        msg += info.pendingCells + " cells in iterative calculation round " + info.iterate; 
    } else { 
        msg += (info.totalCells - info.pendingCells) + "/" + info.totalCells + "cells"; 
    } 
    console.log(msg); 
}); 
```

## 상태 표시줄 항목 추가

`incrementalCalculation` 옵션이 `true`로 설정된 경우, 점진적 계산은 계산 진행 상황을 나타내기 위해 상태 표시줄에도 표시됩니다.
다음 코드 샘플은 상태 표시줄을 Spread에 바인딩하여 자동으로 계산 진행 상황을 표시하는 방법을 보여줍니다:

```javascript
// 상태 표시줄을 초기화하고 Spread에 바인딩합니다.
var statusBar = new GC.Spread.Sheets.StatusBar.StatusBar(document.getElementById('statusBar'));
statusBar.bind(spread);
```

**순환 참조가 없는 셀의 경우**: 계산 진행 상황은 아래 이미지와 같이 백분율 형식으로 표시됩니다:
![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/d37fbce1-6a37-43ce-b728-dd79fba68421/image.17b44a.png?width=860)
**순환 참조가 있는 셀의 경우:** `iterativeCalculation`을 `true`로 설정하여 반복 계산을 구현하며, 계산 진행 상황은 다음 GIF와 같이 반복 라운드(Iterative rounds)로 표시됩니다:
![incrementalcalculation-circular.7fccbf.gif](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/incrementalcalculation-circular.7fccbf.a9c3cc.gif)
다음 코드 샘플은 순환 참조에 대해 `iterativeCalculation`을 설정하는 방법을 보여줍니다:

```javascript
// IterativeCalculation 활성화
spread.options.iterativeCalculation = true;
spread.options.iterativeCalculationMaximumIterations = 24;
```

## Wer Worker에서 점진적 계산 실행 (calcWorker 플러그인)

**calcWorker** 플러그인은 스프레드시트 계산을 Web Worker로 오프로딩하여, 대규모 재계산 중에도 메인 스레드의 응답성을 유지합니다.
대용량이거나 수식이 많은 통합 문서에서 작업할 때 성능을 향상시키고 UI 멈춤을 방지하려면 이 플러그인을 활성화하세요.

>type=note
> 버전 19부터 사용 가능합니다.

**활성화 옵션:**
**옵션 1 – 스크립트 파일 사용**

1. HTML 파일에 플러그인을 가져옵니다.
2. `incrementalCalculation` 옵션을 `true`로 설정합니다.

```html
<script src="gc.spread.sheets.all.xx.x.x.min.js"></script>
<script src="plugins/gc.spread.sheets.calcworker.xx.x.x.min.js"></script>
<script>
window.onload = function () {
    var spread = new GC.Spread.Sheets.Workbook(document.getElementById('ss'), { sheetCount: 1 });
    spread.options.incrementalCalculation = true;
};
</script>
```

**옵션 2 – NPM 패키지 사용**

1. 플러그인을 설치합니다:

```bash
npm install @mescius/spread-sheets-calc-worker
```

2. 코드에서 가져와 활성화합니다:

```javascript
import '@mescius/spread-sheets-calc-worker';
spread.options.incrementalCalculation = true;
```

**확인**
성공적으로 활성화되면 계산 작업이 브라우저의 백그라운드 스레드에서 비동기적으로 실행됩니다. 브라우저 DevTools에서 `calcWorker.js` 스레드가 있는지 확인하여 워커가 활성화되었는지 확인할 수 있습니다.
**기능**

* `incrementalCalculation`이 활성화되면 SpreadJS는 메인 스레드 대신 Web Worker 내부에서 수식 재계산을 수행합니다.
    * 이를 통해 사용자 상호작용이 진행되는 동안에도 셀의 증분 업데이트가 부드럽게 이루어집니다.
    * 계산은 비동기적으로 실행되며, 완료되면 결과가 메인 스레드로 반환됩니다.
* `incrementalCalculation`이 비활성화되면 모든 계산은 메인 스레드에서 직접 실행됩니다.

>type=note
> **참고**:
> `waitForAllCalculations()` 메서드를 사용하여 모든 대기 중인 계산이 완료될 때까지 기다릴 수 있습니다. 이 API는 Promise를 반환하며, 메인 스레드의 `incrementalCalculation`에서도 동작합니다.

**동작 및 제한 사항**

* **계산 우선순위** - `calcOnDemand`는 `incrementalCalculation`보다 우선순위가 낮습니다. `incrementalCalculation`이 활성화되면 `calcOnDemand` 옵션은 자동으로 비활성화됩니다.
* **계산 일시 중단** - `spread.suspendCalcService()`를 사용하여 모든 워커 기반 계산을 일시적으로 중단할 수 있습니다.
* **수동 계산 모드** \- 계산 모드가 “**수동**”으로 설정된 경우 CalcWorker는 자동 재계산을 실행하지 않습니다.
* **데이터 전달 제한** \- 워커로 전달되는 값은 직렬화 가능해야 합니다\. 함수나 복잡한 개체\(예: 클로저\)는 셀 값으로 지원되지 않습니다\.

```javascript
sheet.setValue(1,1,{a:1,f:()=>{return 2;}}); // 워커 모드에서는 유효하지 않음
```

* **계산된 값에 의존하는 API** \- 최신 계산 결과에 의존하는 작업\(예: 정렬\, 내보내기\, 요약\)을 실행하기 전에 `waitForAllCalculations()`를 await로 호출하여 모든 워커 작업이 완료되었는지 확인하세요.

```javascript
sheet.suspendPaint();
for (let i = 0; i < 100; i++) {
    sheet.setFormula(i, 0, `=${100 - i}`);
}
sheet.resumePaint();
await spread.waitForAllCalculations();
sheet.sortRange(0, 0, 100, 1, true, [{ index: 0, ascending: true }]);
```

* **사용자 정의 함수** \- 사용자 정의 함수는 메인 스레드에서 실행됩니다\. CalcWorker에서 수식이 사용자 정의 함수를 만나면\, 해당 계산은 UI 스레드로 위임되며 결과가 다시 워커로 반환됩니다\.
* **조건부 서식 및 시각적 요소** \- 조건부 서식\, 도형 및 차트는 항상 CalcWorker의 최신 결과를 사용하여 메인 스레드에서 처리 및 새로 고침됩니다\.

**예제: 성능 비교**
다음 예제는 calcWorker 플러그인이 대규모 재계산 중 응답성을 어떻게 향상시키는지 보여줍니다.
이 통합 문서에는 `RAND()` 함수를 사용하여 임의 값을 생성하고 확률 및 표준 편차와 같은 통계 계산을 수행하는 **10,000행**의 데이터가 포함되어 있습니다.
![dataShow.29c163.gif](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/36b63360-fb01-457c-a448-c3ce32aaf454/dataShow.29c163-20251216.b8a253.gif?width=1000)
기본 수식 중 하나를 편집하거나 임의 입력을 업데이트하는 등 재계산을 수행하면, 스프레드시트는 수천 개의 종속 수식 업데이트와 차트 새로 고침을 트리거합니다.

| **모드** | **결과** | **설명** |
| --- | --- | --- |
| CalcWorker 미사용(메인 스레드) | ![mainThread.234a60.gif](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/36b63360-fb01-457c-a448-c3ce32aaf454/mainThread.234a60-20251216.99a624.gif?width=500) | 모든 계산이 완료될 때까지 UI가 잠시 멈춥니다. 스크롤하거나 셀을 선택하는 동작이 응답하지 않게 됩니다. |
| CalcWorker 사용(Web Worker) | ![calcWorker.256a1e.gif](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/36b63360-fb01-457c-a448-c3ce32aaf454/calcWorker.256a1e-20251216.120147.gif?width=500) | 계산이 백그라운드에서 비동기적으로 실행되어 인터페이스가 부드럽게 유지됩니다. 시트가 계속 업데이트되는 동안에도 이동, 스크롤 및 결과 확인이 가능합니다. |
