How to pass functions to JavaScript Web Worker

后端 未结 3 1517
抹茶落季
抹茶落季 2021-02-02 09:35

I would like to pass a function (or functions) via a postMessage() to a web worker, because I can\'t refer to regular files.

To kick the web worker off, I a

相关标签:
3条回答
  • 2021-02-02 10:15

    Yes, of course it is possible, I implemented it

    This is a promise that will execute the generic worker

    /*
        @data.context, The context where the callback functions arguments are, ex: window
        @data.callback, ["fn_name1", "fn_name2", function (fn1, fn2) {}]
            The callback will be executed, and you can pass other functions to that cb
        @worker_url string url of generic web worker
    */
    function genericWorker(worker_url, data) {
        return new Promise(function (resolve, reject) {
    
            if (!data.callback || !Array.isArray(data.callback))
                return reject("Invalid data")
    
            var callback = data.callback.pop()
            var functions = data.callback
            var context = data.context
    
            if (!worker_url)
                return reject("Worker_url is undefined")
    
            if (!callback)
                return reject("A callback was expected")
    
            if (functions.length>0 && !context)
                return reject("context is undefined")
    
            callback = fn_string(callback) //Callback to be executed
            functions = functions.map((fn_name)=> { return fn_string( context[fn_name] ) })
    
            var worker = new Worker(worker_url)
    
            worker.postMessage({ callback: callback, functions: functions })
    
            worker.addEventListener('error', function(error){
                return reject(error.message)
            })
    
            worker.addEventListener('message', function(e) {
                resolve(e.data)
                worker.terminate()
    
            }, false)
    
    
            //From function to string, with its name, arguments and its body
            function fn_string (fn) {
                var name = fn.name
                fn = fn.toString()
    
                return {
                    name: name,
                    args: fn.substring(fn.indexOf("(") + 1, fn.indexOf(")")),
                    body: fn.substring(fn.indexOf("{") + 1, fn.lastIndexOf("}"))
                }
            }
    
        })
    }
    

    The generic worker file worker_for_anything.js

    self.addEventListener('message', function(e) {    
        var worker_functions = {} //Functions used by callback
        var args = [] //Arguments of the callback
    
        for (fn of e.data.functions) {
            worker_functions[fn.name] = new Function(fn.args, fn.body)
            args.push(fn.name)
        }
    
        var callback = new Function( e.data.callback.args, e.data.callback.body) //Callback passed and ready to be executed    
        args = args.map((fn_name) => { return worker_functions[fn_name] }) //FUnctions loaded as arguments
        var result = callback.apply(null, args) //executing callback with function arguments
        self.postMessage( result )
    
    }, false)
    

    Using it :)

    var data = {
        context: window, //the context of the functions passed, ex: window for blockCpu
        callback: ["blockCpu", function (bla) {
            bla(7000) //blocking for 7000 ms
            return "bla" //This return is catched in the promise
        }]
    }
    
    genericWorker("/worker_for_anything.js", data)
        .then(function (result){
            console.log("result", result)
    
        }).catch((error)=> { console.log(error) })
    
    //random blocking function
    function blockCpu(ms) {
        var now = new Date().getTime();
        var result = 0
        while(true) {
            result += Math.random() * Math.random();
            if (new Date().getTime() > now +ms)
                return;
        }   
    }
    
    0 讨论(0)
  • 2021-02-02 10:16

    For those who are looking for more generic answer: here is a plugin, which allows you to execute any function of your javascript code in a thread.

    http://www.eslinstructor.net/vkthread/

    Consider it as "function outsourcing". You pass any function to the plugin as an argument and get result in callback. You also can "outsource" object's methods, function with dependecies, anonymous function and lambda.

    Enjoy.

    --Vadim

    0 讨论(0)
  • 2021-02-02 10:21

    Turns out this method works fine, there was merely a bug in my worker:

    var result = greeter("john");
    

    should be

    var result = greet("john");
    

    which makes sense - I'm passing the greeter variable to the worker, but there's no reason for it to know the variable name of the object I'm passing.

    0 讨论(0)
提交回复
热议问题