2

I want to use a WebWorker inside a WebExtension on a Azure DevOps Server.

Processing data of a large repository cost a lot, so I want to use a WebWorker to calculate in Background.

But when I call new Worker("static/js/WorkerLoadTree.js"):

//CREATE WORKER
console.log("BEFORE NEW WORKER CALL")
BackgroundWorker = new Worker("static/js/WorkerLoadTree.js");
console.log("AFTER NEW WORKER CALL")

I see in Edge:

enter image description here

and I see in Chrome a bit more details:

VSS.SDK.min.js:2 Rejected XDM promise with no reject callbacks                                                  n._reject @ VSS.SDK.min.js:2
VSS.SDK.min.js:2 DOMException: Failed to construct 'Worker': Script at 'http://136.310.18.216:8070/_apis/public/gallery/publisher/user/extension/SearchRepos/1.0.13/assetbyname/static/js/WorkerLoadTree.js' cannot be accessed from origin 'null'.
    at WorkerStart (http://136.310.18.216:8070/_apis/public/gallery/publisher/user/extension/SearchRepos/1.0.13/assetbyname/static/js/WorkerMain.js:13:32)
    at FillCode (http://136.310.18.216:8070/_apis/public/gallery/publisher/user/extension/SearchRepos/1.0.13/assetbyname/index.html:284:3)
    at http://136.310.18.216:8070/_apis/public/gallery/publisher/user/extension/SearchRepos/1.0.13/assetbyname/index.html:144:6
    at n._wrapCallback (http://136.310.18.216:8070/_apis/public/gallery/publisher/user/extension/SearchRepos/1.0.13/assetbyname/lib/VSS.SDK.min.js:2:951)
    at Array.<anonymous> (http://136.310.18.216:8070/_apis/public/gallery/publisher/user/extension/SearchRepos/1.0.13/assetbyname/lib/VSS.SDK.min.js:2:647)
    at http://136.310.18.216:8070/_apis/public/gallery/publisher/user/extension/SearchRepos/1.0.13/assetbyname/lib/VSS.SDK.min.js:2:1383            n._reject @ VSS.SDK.min.js:2
Failed to load resource: net::ERR_UNEXPECTED                                                            :8070/DefaultCollection/_apis/Contribution/HierarchyQuery/project/09737d31-b39f-49a1-8973-4a702cc4be92:1

It seems to be something wrong to load the WorkerLoadTree.js. Is the way to call correct? How can the worker access a js-file inside an extension?

My Extension File-Structure looks like:

───SearchRepos
    │   icon.png
    │   index.html
    │   SearchRepos-1.0.14.vsix
    │   package-lock.json
    │   package.json
    │   vss-extension.json
    │
    ├───node_modules
    │   └───vss-web-extension-sdk
    │       ...
    │
    └───static
        ├───css
        │       main.css
        │
        ├───js
        │       main.js
        │       WorkerLoadCode.js <- WebWorker
        │       WorkerLoadTree.js <- WebWorker
        │       WorkerMain.js
        │
        ├───lib
        │       jquery-3.4.1.min.js
        │       jstree.js
        │
        └───themes
        ...

Meta:

Azure DevOps Server 17.143.28912.1 (AzureDevOps2019.0.1)

Mar Tin
  • 2,132
  • 1
  • 26
  • 46

2 Answers2

1

DOMException: Failed to construct 'Worker': Script at 'http://136.310.18.216:8070/_apis/xxxx/static/js/WorkerLoadTree.js' cannot be accessed from origin 'null'.

This is a very normal error about access file across domain. Use web worker has one limitation : Same Origin Policy. And also the browser does not allow to create a worker with a URL which pointing to a different domain. This "across domain" error caused by your call way is not correct.

BackgroundWorker = new Worker("static/js/WorkerLoadTree.js");

Chrome doesn't let you load web workers when running scripts from a local file(), or the error will like this:

enter image description here

Note: I just do a example in my local machine. Loading a local file, even with a relative URL, is same as loading a file with the file: protocol.

You should use the url which from the webserver where these files put, like this: http://xxxx:xx/static/js/WorkerLoadTree.js. Or the chrome will consider this local file called way as using file across domain.

Mengdi Liang
  • 17,577
  • 2
  • 28
  • 35
  • thanks for your respone. I can comprehend everything you write and everything is correct. Yesterday I checkout this issue and find this [workaround](https://stackoverflow.com/questions/21408510/chrome-cant-load-web-worker) where the webworker get loaded as **blob**: `new Worker(URL.createObjectURL(new Blob(["("+worker_function.toString()+")()"], {type: 'text/javascript'})));`. And locally it work fine. Chrome can execute the worker. But as DevOps Webextension I still get: `Rejected XDM promise with no reject callbacks` and `code: 18, message: "SecurityError", name: "SecurityError"` – Mar Tin Sep 06 '19 at 09:49
  • 1
    Dis you set the webserver and put the files there? What's your url used? – Mengdi Liang Sep 06 '19 at 09:53
  • As Webextension, Azure DevOps manage the putting of the files to the webserver by the self, or I understand something wrong? – Mar Tin Sep 06 '19 at 09:57
  • 1
    No, as what you mentioned in question, you upload the extension files in TFS server. For TFS, it is a local server instead of a web server. – Mengdi Liang Sep 06 '19 at 11:04
  • 1
    @MarTin How the things going now? Did you set IIS server in TFS server then put the files there? Feel free to share us your process thus other SO users could help you. – Mengdi Liang Sep 10 '19 at 08:44
  • Unfortunately I dont have much experiance in setting up a IIS server. So I investigate alternatives to web workers and stop follow my old approach. What works OKisch now for me is a simple `setTimout(func, ms)` approach. The web extension still useable while processing. The only reason to get web worker works that say maybe run fast than the `setTimeout` approach. I can't answer that but, currently I am satisfied with this solution, thanks for your help @MerlinLiang-MSFT. – Mar Tin Sep 10 '19 at 09:31
  • You're welcome. Glad hear you have work around to achieve the worker worked. I'd rather recommend you convert the work around as answer and accept it. You know, this is a very normal issue that maybe many other SO users meet it. Thus other users can refer to your work around. – Mengdi Liang Sep 10 '19 at 09:42
  • I will do if I have a bit time. :-) – Mar Tin Sep 10 '19 at 10:04
1

Finally I stoped to follow the WebWorker approach. I couldn't get it work inside a Azure DevOps WebExtension. Instead I use the requestIdleCallback / setTimeout aproach, which is working well in my usecase.

For that you need two functions.

First:

function TaskCaller() {
    //TASK CALLER
    TaskRunner(0, int Interations);
}

and second:

function TaskRunner(xCount, xEnd) {
    //TASK RUNNER
    xCount++;

    //ENTER CODE HERE
    console.log(xCount)

    //NEXT ITERATION
    if (xCount < xEnd)
        if (xCount % 1000) setTimeout(function () { TaskRunner(xCount, xEnd) }, 0);
        else TaskRunner(xCount, xEnd);
}

I realised that for task it's enough when the task runner call a timeout every 1000 nd iteration. I could still control the page while the runner calculate in background.

There are much better solutions out there, for instance background.js, but for now it's okay.

Mar Tin
  • 2,132
  • 1
  • 26
  • 46