How to pass functions to JavaScript Web Worker

后端 未结 3 1519
抹茶落季
抹茶落季 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;
        }   
    }
    

提交回复
热议问题