function invokeFromWorker(workerType, isDataUrl, workerOptions,
                          subresource, sourceContextList) {
  const currentSourceContext = sourceContextList[0];
  let workerUrl =
    "/common/security-features/scope/worker.py?policyDeliveries=" +
    encodeURIComponent(JSON.stringify(
        currentSourceContext.policyDeliveries || []));
  if (workerOptions.type === 'module') {
    workerUrl += "&type=module";
  }

  let promise;
  if (isDataUrl) {
    promise = fetch(workerUrl)
      .then(r => r.text())
      .then(source => {
          return 'data:text/javascript;base64,' + btoa(source);
        });
  } else {
    promise = Promise.resolve(workerUrl);
  }

  return promise
    .then(url => {
      if (workerType === "worker") {
        const worker = new Worker(url, workerOptions);
        worker.postMessage({subresource: subresource,
                            sourceContextList: sourceContextList.slice(1)});
        return bindEvents2(worker, "message", worker, "error", window, "error");
      } else if (workerType === "sharedworker") {
        const worker = new SharedWorker(url, workerOptions);
        worker.port.start();
        worker.port.postMessage({subresource: subresource,
                                 sourceContextList: sourceContextList.slice(1)});
        return bindEvents2(worker.port, "message", worker, "error", window, "error");
      } else {
        throw new Error('Invalid worker type: ' + workerType);
      }
    })
    .then(event => {
        if (event.data.error)
          return Promise.reject(event.data.error);
        return event.data;
      });
}
@param {string} workerType
    "worker" (for dedicated worker) or "sharedworker".
  @param {boolean} isDataUrl
    true if the worker script is loaded from data: URL.
    Otherwise, the script is loaded from same-origin.
  @param {object} workerOptions
    The `options` argument for Worker constructor.

  Other parameters and return values are the same as those of invokeRequest().