[]
        
(Showing Draft Content)

Calc Worker의 사용자 정의 함수

calcWorker 플러그인이 로드되고 incrementalCalculation이 활성화된 경우, SpreadJS는 메인 스레드 대신 Web Worker 내부에서 수식을 계산합니다.

이 모드에서는 기본 제공 수식이 Calc Worker 내부에서 직접 실행됩니다. 반면 사용자 정의 함수(Custom Function)는 메인 스레드에서 계산됩니다. Worker가 사용자 정의 함수를 만나면 실행이 UI 스레드로 위임되고, 결과가 다시 Worker로 반환됩니다.

SpreadJS 19.1.0부터는 조건을 만족하는 사용자 정의 함수를 Calc Worker 내부에서 직접 실행할 수 있습니다. 이를 통해 Worker와 UI 스레드 간의 메시지 전달이 제거되어, 사용자 정의 함수가 자주 호출되는 경우 통신 오버헤드를 줄일 수 있습니다.

요구 사항

사용자 정의 함수는 다음 조건을 모두 만족할 때만 Calc Worker 내부에서 실행됩니다.

  1. calcWorker 플러그인이 로드되어 있어야 합니다.

  2. spread.options.incrementalCalculation = true가 설정되어 있어야 합니다.

  3. Custom Function의 supportCalcWorker()true를 반환해야 합니다.

참고:

  • incrementalCalculation이 비활성화된 경우 supportCalcWorker()는 무시됩니다.

  • calcWorker 플러그인이 로드되지 않은 경우 계산은 항상 메인 스레드에서 실행됩니다.

실행 모델

supportCalcWorker()true를 반환하면 함수 구현이 직렬화되어 Calc Worker에 로드됩니다. 이후 실행은 Worker 스레드 내부에서 완전히 수행됩니다.

영향 사항

  • 필요한 모든 로직은 evaluate() 또는 evaluateAsync() 내부에 정의되어 있어야 합니다.

  • prototype 및 instance 멤버는 유지되지 않습니다.

  • Workbook, Worksheet, GC.Spread.Sheets API는 사용할 수 없습니다.

  • 평가 컨텍스트, 인수 및 Web Worker 기본 제공 API만 사용할 수 있습니다.

도우미 메서드는 함수 본문 내부에 정의해야 합니다.

지원되는 반환 형식

Calc Worker 내부에서 실행되는 사용자 정의 함수는 다음 결과 형식을 반환할 수 있습니다.

  • 기본 값(string, number, boolean, null)

  • GC.Spread.CalcEngine.CalcArray

  • GC.Spread.CalcEngine.Errors.*

CalcArrayCalcError 객체는 Calc Worker 내부 실행 시 완전히 지원되며 메인 스레드 계산과 동일하게 동작합니다.

복잡한 결과를 반환하는 경우 해당 값이 지원되는 CalcEngine 형식이거나 Worker 환경에서 직렬화 가능한 값인지 확인해야 합니다.

Worker 실행 활성화

다음에서 사용할 수 있습니다.

  • GC.Spread.CalcEngine.Functions.Function

  • GC.Spread.CalcEngine.Functions.AsyncFunction

supportCalcWorker() {
    return true;
}

메타데이터 전달 동작

사용자 정의 함수가 Calc Worker 내부에서 실행될 경우:

  • 평가 메서드는 Worker 스레드에서 실행됩니다.

  • 지원되는 함수 메타데이터는 자동으로 전달됩니다.

  • prototype 확장 및 지원되지 않는 동작은 사용할 수 없습니다.

Worker 실행을 활성화할 때는 prototype 기반 로직이나 UI 스레드 동작에 의존하지 마세요.

예제

기본 예제: Calc Worker에서 실행되는 유틸리티 함수

function Base64Decode() {}
Base64Decode.prototype =
    new GC.Spread.CalcEngine.Functions.Function("BASE64DECODE", 1, 1);

Base64Decode.prototype.supportCalcWorker = function () {
    return true;
};

Base64Decode.prototype.evaluate = function (value) {
    if (typeof value !== "string") {
        return "#VALUE!";
    }
    try {
        return atob(value);
    } catch {
        return "#VALUE!";
    }
};

sheet.addCustomFunction(new Base64Decode());
spread.options.incrementalCalculation = true;

확장 예제: 첫 번째 계산 시 함수 및 전역 캐시 초기화

class Hash extends GC.Spread.CalcEngine.Functions.AsyncFunction {
    constructor() {
        super("HASH", 1, 1);
    }

    supportCalcWorker() {
        return true;
    }

    evaluateAsync(context, input) {
        const global = globalThis;

        if (!global.cache) {
            global.cache = {};
        }

        if (global.cache[input]) {
            return global.cache[input];
        }

        const encoder = new TextEncoder();
        const data = encoder.encode(String(input));

        crypto.subtle.digest("SHA-256", data).then(buffer => {
            const hex = Array.from(new Uint8Array(buffer))
                .map(b => b.toString(16).padStart(2, "0"))
                .join("");

            global.cache[input] = hex;
            context.setAsyncResult(hex);
        }).catch(() => {
            context.setAsyncResult("#HASH_ERROR!");
        });
    }
}

GC.Spread.CalcEngine.Functions.defineGlobalCustomFunction("HASH", new Hash());

설계 지침

Worker 호환 사용자 정의 함수를 작성할 때는 다음 사항을 권장합니다.

  • 구현을 독립적으로 유지

  • 평가 메서드 내부에 도우미 로직 정의

  • Worker에서 안전하게 사용할 수 있는 API만 사용

  • UI 스레드 의존성 제거

  • 직렬화 가능한 값 사용

Worker 실행은 메인 스레드 위임이 병목이 되는 대규모 또는 수식 밀도가 높은 통합 문서에서 가장 효과적입니다.

성능 고려 사항

사용자 정의 함수에 대해 Worker 실행을 활성화하면 Calc Worker와 UI 스레드 간의 교차 스레드 통신이 제거됩니다.

supportCalcWorker()를 사용하지 않는 경우:

  • Worker는 사용자 정의 함수를 만나면 일시 중지됩니다.

  • 실행이 메인 스레드로 위임됩니다.

  • 결과가 다시 Worker로 반환됩니다.

이 과정에서 호출마다 메시지 전달 오버헤드가 발생합니다.

supportCalcWorker()를 활성화한 경우:

  • 함수가 Worker 내부에서 완전히 실행됩니다.

  • 교차 스레드 메시지 전달이 발생하지 않습니다.

다음과 같은 경우 성능 향상 효과가 가장 큽니다.

  • 사용자 정의 함수가 많은 셀에서 호출되는 경우

  • 함수 구현은 가볍지만 호출 빈도가 높은 경우

  • 큰 종속성 체인으로 인해 반복 계산이 발생하는 경우

실제 성능 향상은 호출 횟수 및 함수 복잡도에 따라 달라집니다.

다음은 여러 종속 셀을 포함한 HASH 계산 시나리오의 비교 예제입니다.

comparsionExample-20260318.7a445d.gif