Implementing a WebWorker in Kotlin

The JavaScript worker API is exposed to Kotlin and I can easily create web workers with it. Can I also write the worker’s code in Kotlin?

Yes, you can. Why not?

Thank you for your response! After some more thinking I think my problems are the following:

  1. I don’t know how to put my code into the right context. How can I tell the compiler that self has a method addEventListener and a method postMessage?
  2. Would my project then have two main functions, one for the main web page and one for the worker thread? If so, how can I configure IntelliJ to compile the two main functions into two separate output files?

As I’m typing this, I think that I could probably solve problem 1 with inline JavaScript that just expects these variables to be set. :thinking:

I don’t know how to put my code into the right context. How can I tell the compiler that self has a method addEventListener and a method postMessage?

external val self: ServiceWorkerGlobalScope

Would my project then have two main functions, one for the main web page and one for the worker thread? If so, how can I configure IntelliJ to compile the two main functions into two separate output files?

There are number of ways. First, you don’t necessarily need main function, the following trick also works fine:

private val dummy = start()

fun start() {
    // do something
}

Second, you don’t need main function in non-worker script at all. You can define a function and call it, say, from another <script> tag or from <body onload="...">.

Third, you can put worker in a separate module.

3 Likes

Maybe this is a bit of an old thread, but I found the perfect solution for me:

external val self: ServiceWorkerGlobalScope
fun runAsync(run: () -> Unit) {
    var worker: Worker? = null
    fun terminate() = worker!!.terminate()

    worker = Worker(
        URL.createObjectURL(
            Blob(
                arrayOf(
                    {
                        self.onmessage = {
                            run()
                            terminate()
                        }
                    }()
                ),
                jsObject { type = "text/javascript" }
            )
        )
    ).apply {
        postMessage(null)
    }
}

This function can be used like this:

runAsync {
    println("hello from async")
}

This can be improved as I do get a reference error that “kotlin isn’t found”, but the code successfully executes, so I think we can just catch this exception.
Anyways, hope this helps you!

Edit: actually, this doesn’t work perfectly… We need a way to pass in parameters to make it thread safe
Edit 2: Okay, I’ve been looking into it, but it’s harder than expected. I tried converting https://github.com/boneVidy/inline-webworker this typescript library to Kotlin, but I ran into some issues. For instance, the tasks function task: Function needs a reference to self: InlineWorker so it can run postMessage (compared to the TS I see it like this typealias Function = (self: InlineWebWorker) -> Unit), but when I provide task() with this to put in the blob array arrayOf({ task(self = this) }()), then the task function already gets executed on this thread instead of on the second thread like how it’s supposed to work.
Basically, the only way my example above works is because I assign the function to self.onmessage and thus the function only gets executed when onmessage fires on the second thread. So yeah, any ideas would be welcome.
Edit 3: Added terminate() to example

Edit 4: I don’t think this is working at all as my page still gets stuck executing it…
There is this https://github.com/korlibs/kworker library but it’s not finished and doesn’t work on browser only without removing the cluster dependency in the code. It works, but only for small stuff. See, only certain types are allowed to be pushed as messages, only Ints, Doubles, Strings and ByteArrays are allowed. So to push a large number of objects, they need to be converted to JSON or something, making it slower than simply running it on the main thread… There is a way to use transferable objects in JS that somehow passes the reference to an object in a message, but KWorker doesn’t support this I think. Plus this is hard already in JS, let alone Kotlin/JS.
This just needs an easy to use lbrary or something as it’s getting ridiculous how difficult this is.

1 Like

Maybe someone can make a wrapper for comlink: https://davidea.st/articles/comlink-simple-web-worker
It looks promising, would be awesome if it could work in kotlin :slight_smile: It even allows multiple threads to access the same object! I’ll give it a try when/if I have time.
NVM, comlink is breaking my brain… with all the async stuff going on, I’m not sure if it’s even compatible with kotlin.

Greenlet https://github.com/developit/greenlet also looks interesting. Looks more like coroutines, however I’m not sure if it also destroys Object instances to just their parameters like workers do in postMessage.

1 Like

I’m reviving this thread since it’s the top google result for “KotlinJS WebWorkers”: I’ve created a demo that shows how to use webworkers in a Kotlin/JS project: GitHub - ethanmdavidson/KotlinJSWebWorkerDemo: A simple demo that shows how WebWorkers can be used in Kotlin/JS

It works by putting the worker in a separate module, as suggested by Alexey.Andreev