Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uncaught TypeError: importScripts.map is not a function(…) #36

Closed
pkerpedjiev opened this issue Nov 29, 2016 · 26 comments
Closed

Uncaught TypeError: importScripts.map is not a function(…) #36

pkerpedjiev opened this issue Nov 29, 2016 · 26 comments

Comments

@pkerpedjiev
Copy link

I'm trying to use threads.js do some some processing but am encountering this error:

Uncaught TypeError: importScripts.map is not a function(…)

The workflow goes like this. I first import Pool from the threads module:

import {Pool} from 'threads';

And then call it as in the documentation:

 let jobA = this.threadPool.run(function(input, done) {
                workerGetTilesetInfo(input);
                done(input);
            }, {
                workerGetTilesetInfo: 'worker'
            })

           .on('done', function(job, message) {
                console.log('done', message);
           })
           .on('error', function(job, error) {
                console.log('error', error);
           })
            .send(outUrl);

The function getTilesetInfo is defined in another javascript file called worker.js. Is this a valid issue, or am I simply doing something wrong?

@andywer
Copy link
Owner

andywer commented Nov 29, 2016

Hi @pkerpedjiev.

Considering the Uncaught TypeError: importScripts.map is not a function(…). Could you please expand the stack trace (by clicking on the (...)) and post it here, too?

@pkerpedjiev
Copy link
Author

pkerpedjiev commented Nov 29, 2016

Yup, absolutely:

playground.js:109786Uncaught TypeError: importScripts.map is not a function
    at Worker.runMethod (http://localhost:9000/scripts/playground.js:109786:31)
    at Worker.run (http://localhost:9000/scripts/playground.js:109767:13)
    at Job.executeOn (http://localhost:9000/scripts/playground.js:109437:155)
    at Pool.dequeue (http://localhost:9000/scripts/playground.js:108993:10)
    at Pool.queueJob (http://localhost:9000/scripts/playground.js:108966:11)
    at Job.<anonymous> (http://localhost:9000/scripts/playground.js:109001:22)
    at Job.emit (http://localhost:9000/scripts/playground.js:109182:36)
    at Job.send (http://localhost:9000/scripts/playground.js:109430:11)
    at Pool.send (http://localhost:9000/scripts/playground.js:108955:22)
    at TileProxy.trackInfo (http://localhost:9000/scripts/playground.js:108273:17)

@andywer
Copy link
Owner

andywer commented Nov 29, 2016

Hmm, seems like the documentation suggests a different usage then there is implemented... 👉 worker.spec.js#L230

@andywer
Copy link
Owner

andywer commented Nov 29, 2016

Try passing importScripts as an array for now. But this is definitely not your fault, thanks for reporting 😉

@andywer andywer added the bug label Nov 29, 2016
@pkerpedjiev
Copy link
Author

pkerpedjiev commented Nov 29, 2016

Thanks for the fast responses!

I just tried doing this:

        let jobA = this.threadPool.run(function(input, done) {
                workerGetTilesetInfo(input);
                done(input);
            }, ['scripts/worker.js'])

But now I get this error:

"Uncaught SyntaxError: Failed to execute 'importScripts' on 'WorkerGlobalScope': The URL 'scripts/worker.js' is invalid."

The script is definitely present at http://localhost:9000/scripts/worker.js. Is this an inaccurate path that I'm passing?

@andywer
Copy link
Owner

andywer commented Nov 29, 2016

You could try /scripts/worker.js (leading slash). Maybe that's it.

@pkerpedjiev
Copy link
Author

pkerpedjiev commented Nov 29, 2016

Same error :-/ It doesn't seem to be related to your package, so don't worry about it. I'll google around and see what I can come up with.

Edit:

@andywer, This Stack Overflow question implies that it doesn't work because the script path is taken relative to the blob path. Could this be the problem here as well?

Here's a simplified example:

index.html:

<html>
    <body>
    <script src="https://cdn.rawgit.com/andywer/threads.js/v0.7.2/dist/threads.browser.js"></script>

    Hi there
<script>
    var pool = new thread.Pool(1);

        pool.run(function(input, done) {
                    console.log('hi');
                    console.log(addOne(input));

                 }, ['worker.js'])
           .on('done', function(job, message) {
                console.log('done', message);
           })
           .on('error', function(job, error) {
                console.log('error', error);
           })
            .send(1);

</script>
    </body>
</html>

worker.js:

function addOne(x) {
    return x+1;
}

@pkerpedjiev
Copy link
Author

Can you reproduce the simplified example above @andywer ? Do you think it can be fixed as in the Stack Overflow question or is it a deeper issue?

@andywer
Copy link
Owner

andywer commented Dec 2, 2016

Hey @pkerpedjiev. Yes, I was able to reproduce it: http://www.webpackbin.com/4k8GdX9Mz

The fix mentioned in the SO post should also work when incorporated into threads.js. Just got to find some time to do so...

@andywer
Copy link
Owner

andywer commented Dec 2, 2016

(Need to click on "Log" (in the header) to see the output)

@andywer
Copy link
Owner

andywer commented Dec 2, 2016

Just recognized: The Stack Overflow solution is only going to work if you serve the worker script file and provide a link to it (like when using the IE fallback). That's actually not so elegant... :-/

Still thinking...

@pkerpedjiev
Copy link
Author

Oh, as opposed to bundling the worker script as its own blob? That would probably be ideal but might be tricky because my worker.js first needs to be generated by the build process (e.g. es6 transpilation and import resolution)

@andywer
Copy link
Owner

andywer commented Dec 5, 2016

Yeah, having to adapt your webpack config for every piece of code you want to run in a thread pretty much destroys the simplicity gained by using this library... 🙈

Maybe it would be best to automatically create absolute URLs for the importScripts. I assume everything works fine when passing absolute URLs as importScripts?

@pkerpedjiev
Copy link
Author

pkerpedjiev commented Dec 5, 2016

Yup. That seems to work fine. 👍

Here's the code:

    var pool = new thread.Pool(1);
    var scriptPath = document.location.href;

    pool.run(function(input, done) {
                importScripts(input.scriptPath + '/worker.js');
                console.log('hi');
                console.log(addOne(input.val));

             })
       .on('done', function(job, message) {
            console.log('done', message);
       })
       .on('error', function(job, error) {
            console.log('error', error);
       })
    .send({scriptPath: scriptPath, val: 1});

@andywer
Copy link
Owner

andywer commented Dec 5, 2016

Then there is at least a solution in sight!

I hope to find some time this week to provide a fix you can test :)

@cozzbie
Copy link

cozzbie commented Feb 8, 2017

Guess this means I am doomed because I need to use an npm module and I am getting this error. @andywer @pkerpedjiev

@andywer
Copy link
Owner

andywer commented Feb 8, 2017

Ahh, sorry guys 🙈 I will look into it. Was so busy with other stuff lately...

@cozzbie Can you provide a short example of your "I need to use an npm module" situation?

@cozzbie
Copy link

cozzbie commented Feb 8, 2017

Definitely. I am trying to use the keypair npm lib to create a public and private set and its crashing on the devices its running on so yeah...threading.

           const thread = threads.spawn(function (input, done) {
                done(keypair());
            }, { keypair: "keypair" });

            thread.send()
                .on('message', function (response) {
                    console.log("Hope full pairs", response);
                    thread.kill();
                })
                .on('error', function (error) {
                    console.error('Worker errored:', error);
                })
                .on('exit', function () {
                    console.log('Worker has been terminated.');
                });

The error is the same as the one reported above. @andywer

@andywer
Copy link
Owner

andywer commented Feb 8, 2017

@cozzbie God, this documentation is sketchy 🙈🙈 Yeah, I think what you are trying to do does not yet work this way...

You want to do something like in the ThreadPool example, right? I wonder why it is documented there, since there is a part in the README where it says that there is no such thing yet... :-/

@pjm17971
Copy link

pjm17971 commented Jan 8, 2018

@andrakis Any news on this one? The ability to use an npm module within a worker would be very helpful! Basically the same as the pool example, but in a browser.

@andrakis
Copy link

andrakis commented Jan 9, 2018

I'm not sure what I have to do with this discussion...my worker implementation is entirely Node.js side, not browser-side.

@pkerpedjiev
Copy link
Author

A workaround is to create an absolute path for the worker from the current script's path:

const str = document.currentScript.src
const pathName = str.substring(0, str.lastIndexOf("/"));
const workerPath = `${pathName}/worker.js`;

@Luiz-N
Copy link

Luiz-N commented Apr 23, 2018

@pkerpedjiev what is the format of your worker.js file? I'm still getting Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://localhost:4200/assets/vendor/test.js' failed to load. error despite trying to replicate your simple example. Are you able to import other dependencies from within that file as well?

@pkerpedjiev
Copy link
Author

What do you mean? It's a javascript file :)

It needs to be a standalone script. So if you have import statements, those need to be resolved using webpack before the script gets called from the worker.

@Luiz-N
Copy link

Luiz-N commented Apr 23, 2018

thanks i got it working... for anyone else here looking for help another workaround is to pass in cdn links for any external deps. Either in your own dedicated worker file via importScripts() or within

pool.run(function(input, done) {
      let thing = pako.ungzip( input.data );
      return done(thing);
    }, ['https://unpkg.com/pako@1.0.6/dist/pako.js'])
.send(....)

@andywer
Copy link
Owner

andywer commented Jun 30, 2019

v1.0 beta is here with a whole new API. It will make your life much easier, esp. when import-ing modules 😉

Closing.

@andywer andywer closed this as completed Jun 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants