Files
ohif-viewer/platform/docs/docs/development/webWorkers.md
2025-03-07 13:47:44 +07:00

4.0 KiB

sidebar_position, sidebar_label
sidebar_position sidebar_label
13 Web Workers

Web Worker Implementation Guide

Overview

Web Workers enable running computationally intensive tasks in background threads without blocking the UI. This guide explains how to implement them step by step.

Basic Setup

1. Create Your Worker File

First, create a worker file with your background tasks:

// myWorker.js
import { expose } from 'comlink';

const obj = {
  // Simple task
  basicCalculation({ data }) {
    // Your computation here
    return result;
  },

  // Task with progress updates
  longRunningTask({ data }, progressCallback) {
    const total = data.length;

    for (let i = 0; i < total; i++) {
      // Your processing logic

      if (progressCallback) {
        const progress = Math.round((i / total) * 100);
        progressCallback(progress);
      }
    }

    return result;
  }
};

expose(obj);

2. Register the Worker

In the main thread, can be your service, commands module, etc.

import { getWebWorkerManager } from '@cornerstonejs/core';

const workerManager = getWebWorkerManager();

// Define worker creation function
const workerFn = () => {
  return new Worker(
    new URL('./myWorker.js', import.meta.url),
    { name: 'my-worker' }
  );
};

// Registration options
const options = {
  maxWorkerInstances: 1, // Number of concurrent workers
  autoTerminateOnIdle: {
    enabled: true,
    idleTimeThreshold: 3000, // Terminate after 3s idle
  },
};

// Register the worker
workerManager.registerWorker('my-worker', workerFn, options);

:::info It is recommended to register the worker in top of the commands module. So that it gets registered before any commands that need to use the worker. :::

3. Execute Tasks

// Basic execution
try {
  const result = await workerManager.executeTask(
    'my-worker',
    'basicCalculation',
    { data: myData }
  );
} catch (error) {
  console.error('Task failed:', error);
}

// Execution with progress callback
try {
  const result = await workerManager.executeTask(
    'my-worker',
    'longRunningTask',
    { data: myData },
    {
      callbacks: [
        (progress) => {
          console.log(`Progress: ${progress}%`);
        }
      ]
    }
  );
} catch (error) {
  console.error('Task failed:', error);
}

Progress Events (Optional)

If you want to show progress in your UI as a loading spinner, you can implement a progress event system:

1. Publish Progress Events

// Helper to trigger progress events
const publishProgress = (eventTarget, progress, taskId) => {
  triggerEvent(eventTarget, 'WEB_WORKER_PROGRESS', {
    progress,    // number 0-100
    type: 'YOUR_TASK_TYPE', // can be any string identifier
    id: taskId,  // unique task identifier
  });
};

// Usage in your application
async function runTaskWithProgress(data) {
  // Start progress
  publishProgress(eventTarget, 0, data.id);

  try {
    const result = await workerManager.executeTask(
      'my-worker',
      'longRunningTask',
      { data },
      {
        callbacks: [
          (progress) => {
            publishProgress(eventTarget, progress, data.id);
          }
        ]
      }
    );

    // Complete progress
    publishProgress(eventTarget, 100, data.id);

    return result;
  } catch (error) {
    console.error('Task failed:', error);
    throw error;
  }
}

Note: Publishing the WEB_WORKER_PROGRESS event on Cornerstone's eventTarget will automatically trigger the built-in loading spinner. This gives users visual feedback while your worker runs in the background.

Multiple Methods in One Worker

You can define multiple related methods in a single worker file:

// complexWorker.js
import { expose } from 'comlink';

const obj = {
  processingMethod1({ data }, progressCallback) {
    // Implementation
  },

  processingMethod2({ data }, progressCallback) {
    // Implementation
  },

  processingMethod3({ data }, progressCallback) {
    // Implementation
  },

  // Shared helper methods
  _internalHelper() {
    // Helper logic
  }
};

expose(obj);