Skip to content

⬅️ Back to Table of Contents

📄 index.ts

📊 Analysis Summary

Metric Count
🔧 Functions 5
📦 Imports 6
📊 Variables & Constants 1
⚡ Async/Await Patterns 3
📐 Interfaces 1
📑 Type Aliases 2

📚 Table of Contents

🛠️ File Location:

📂 packages/core/useWebWorkerFn/index.ts

📦 Imports

Name Source
ConfigurableWindow ../_configurable
tryOnScopeDispose @vueuse/shared
deepRef vue
shallowRef vue
defaultWindow ../_configurable
createWorkerBlobUrl ./lib/createWorkerBlobUrl

Variables & Constants

Name Type Kind Value Exported
newWorker Worker & { _url?: string } const new Worker(blobUrl)

Async/Await Patterns

Type Function Await Expressions Promise Chains
promise-chain useWebWorkerFn none new Promise(...), Promise.reject
promise-chain callWorker none new Promise(...)
promise-chain workerFn none Promise.reject

Functions

useWebWorkerFn(fn: T, options: UseWebWorkerOptions): { workerFn: (...fnArgs: Parameters<T>) => Promise<ReturnType<T>>; workerStatus: any; workerTerminate: (status?: WebWorkerStatus) => void; }

Code
export function useWebWorkerFn<T extends (...fnArgs: any[]) => any>(fn: T, options: UseWebWorkerOptions = {}) {
  const {
    dependencies = [],
    localDependencies = [],
    timeout,
    window = defaultWindow,
  } = options

  const worker = deepRef<(Worker & { _url?: string }) | undefined>()
  const workerStatus = shallowRef<WebWorkerStatus>('PENDING')
  const promise = deepRef<({ reject?: (result: ReturnType<T> | ErrorEvent) => void, resolve?: (result: ReturnType<T>) => void })>({})
  const timeoutId = shallowRef<number>()

  const workerTerminate = (status: WebWorkerStatus = 'PENDING') => {
    if (worker.value && worker.value._url && window) {
      worker.value.terminate()
      URL.revokeObjectURL(worker.value._url)
      promise.value = {}
      worker.value = undefined
      window.clearTimeout(timeoutId.value)
      workerStatus.value = status
    }
  }

  workerTerminate()

  tryOnScopeDispose(workerTerminate)

  const generateWorker = () => {
    const blobUrl = createWorkerBlobUrl(fn, dependencies, localDependencies)
    const newWorker: Worker & { _url?: string } = new Worker(blobUrl)
    newWorker._url = blobUrl

    newWorker.onmessage = (e: MessageEvent) => {
      const { resolve = () => { }, reject = () => { } } = promise.value
      const [status, result] = e.data as [WebWorkerStatus, ReturnType<T>]

      switch (status) {
        case 'SUCCESS':
          resolve(result)
          workerTerminate(status)
          break
        default:
          reject(result)
          workerTerminate('ERROR')
          break
      }
    }

    newWorker.onerror = (e: ErrorEvent) => {
      const { reject = () => { } } = promise.value
      e.preventDefault()
      reject(e)
      workerTerminate('ERROR')
    }

    if (timeout) {
      timeoutId.value = setTimeout(
        () => workerTerminate('TIMEOUT_EXPIRED'),
        timeout,
      ) as any
    }
    return newWorker
  }

  const callWorker = (...fnArgs: Parameters<T>) => new Promise<ReturnType<T>>((resolve, reject) => {
    promise.value = {
      resolve,
      reject,
    }
    worker.value?.postMessage([[...fnArgs]])

    workerStatus.value = 'RUNNING'
  })

  const workerFn = (...fnArgs: Parameters<T>) => {
    if (workerStatus.value === 'RUNNING') {
      console.error(
        '[useWebWorkerFn] You can only run one instance of the worker at a time.',
      )
      /* eslint-disable-next-line prefer-promise-reject-errors */
      return Promise.reject()
    }

    worker.value = generateWorker()
    return callWorker(...fnArgs)
  }

  return {
    workerFn,
    workerStatus,
    workerTerminate,
  }
}
  • JSDoc:

    /**
     * Run expensive function without blocking the UI, using a simple syntax that makes use of Promise.
     *
     * @see https://vueuse.org/useWebWorkerFn
     * @param fn
     * @param options
     */
    

  • Parameters:

  • fn: T
  • options: UseWebWorkerOptions
  • Return Type: { workerFn: (...fnArgs: Parameters<T>) => Promise<ReturnType<T>>; workerStatus: any; workerTerminate: (status?: WebWorkerStatus) => void; }
  • Calls:
  • deepRef (from vue)
  • shallowRef (from vue)
  • worker.value.terminate
  • URL.revokeObjectURL
  • window.clearTimeout
  • workerTerminate
  • tryOnScopeDispose (from @vueuse/shared)
  • createWorkerBlobUrl (from ./lib/createWorkerBlobUrl)
  • resolve
  • reject
  • e.preventDefault
  • setTimeout
  • worker.value?.postMessage
  • console.error
  • Promise.reject
  • generateWorker
  • callWorker
  • Internal Comments:
    /* eslint-disable-next-line prefer-promise-reject-errors */
    

workerTerminate(status: WebWorkerStatus): void

Code
(status: WebWorkerStatus = 'PENDING') => {
    if (worker.value && worker.value._url && window) {
      worker.value.terminate()
      URL.revokeObjectURL(worker.value._url)
      promise.value = {}
      worker.value = undefined
      window.clearTimeout(timeoutId.value)
      workerStatus.value = status
    }
  }
  • Parameters:
  • status: WebWorkerStatus
  • Return Type: void
  • Calls:
  • worker.value.terminate
  • URL.revokeObjectURL
  • window.clearTimeout

generateWorker(): Worker & { _url?: string; }

Code
() => {
    const blobUrl = createWorkerBlobUrl(fn, dependencies, localDependencies)
    const newWorker: Worker & { _url?: string } = new Worker(blobUrl)
    newWorker._url = blobUrl

    newWorker.onmessage = (e: MessageEvent) => {
      const { resolve = () => { }, reject = () => { } } = promise.value
      const [status, result] = e.data as [WebWorkerStatus, ReturnType<T>]

      switch (status) {
        case 'SUCCESS':
          resolve(result)
          workerTerminate(status)
          break
        default:
          reject(result)
          workerTerminate('ERROR')
          break
      }
    }

    newWorker.onerror = (e: ErrorEvent) => {
      const { reject = () => { } } = promise.value
      e.preventDefault()
      reject(e)
      workerTerminate('ERROR')
    }

    if (timeout) {
      timeoutId.value = setTimeout(
        () => workerTerminate('TIMEOUT_EXPIRED'),
        timeout,
      ) as any
    }
    return newWorker
  }
  • Return Type: Worker & { _url?: string; }
  • Calls:
  • createWorkerBlobUrl (from ./lib/createWorkerBlobUrl)
  • resolve
  • workerTerminate
  • reject
  • e.preventDefault
  • setTimeout

callWorker(fnArgs: Parameters<T>): Promise<ReturnType<T>>

Code
(...fnArgs: Parameters<T>) => new Promise<ReturnType<T>>((resolve, reject) => {
    promise.value = {
      resolve,
      reject,
    }
    worker.value?.postMessage([[...fnArgs]])

    workerStatus.value = 'RUNNING'
  })
  • Parameters:
  • fnArgs: Parameters<T>
  • Return Type: Promise<ReturnType<T>>

workerFn(fnArgs: Parameters<T>): Promise<ReturnType<T>>

Code
(...fnArgs: Parameters<T>) => {
    if (workerStatus.value === 'RUNNING') {
      console.error(
        '[useWebWorkerFn] You can only run one instance of the worker at a time.',
      )
      /* eslint-disable-next-line prefer-promise-reject-errors */
      return Promise.reject()
    }

    worker.value = generateWorker()
    return callWorker(...fnArgs)
  }
  • Parameters:
  • fnArgs: Parameters<T>
  • Return Type: Promise<ReturnType<T>>
  • Calls:
  • console.error
  • Promise.reject
  • generateWorker
  • callWorker
  • Internal Comments:
    /* eslint-disable-next-line prefer-promise-reject-errors */
    

Interfaces

UseWebWorkerOptions

Interface Code
export interface UseWebWorkerOptions extends ConfigurableWindow {
  /**
   * Number of milliseconds before killing the worker
   *
   * @default undefined
   */
  timeout?: number
  /**
   * An array that contains the external dependencies needed to run the worker
   */
  dependencies?: string[]
  /**
   * An array that contains the local dependencies needed to run the worker
   */
  localDependencies?: Function[]
}

Properties

Name Type Optional Description
timeout number
dependencies string[]
localDependencies Function[]

Type Aliases

WebWorkerStatus

type WebWorkerStatus = | 'PENDING'
  | 'SUCCESS'
  | 'RUNNING'
  | 'ERROR'
  | 'TIMEOUT_EXPIRED';

UseWebWorkerFnReturn

type UseWebWorkerFnReturn = ReturnType<typeof useWebWorkerFn>;