31

我想通过 a 将一个(或多个函数)传递postMessage()给网络工作者,因为我无法引用常规文件。

为了启动 Web Worker,我将一个对象 URL(从 Blob 创建)传递给Worker构造函数。然后我传递了一条消息,但到目前为止还没有在消息中添加一个函数。

(JSON) 消息不能直接包含函数(如此规定),虽然 importScripts 理论上是允许的,但到目前为止我在 Chrome 或 Firefox 中使用它还没有成功。

html文件的正文:

<div id="divText">1234</div>
<script>
    var greeter = function greet(name) {
        return "hello " + name;
    };
    function webWorkerWorker() {
        self.postMessage("started1");
        self.onmessage = function(event) {
            importScripts(event.data.content);
            self.postMessage("importScripts success");
            var result = greeter("john");
            self.postMessage(result);
        };
    }
    var functionBody = mylib.extractFunctionBody(webWorkerWorker);
    var functionBlob = mylib.createBlob([functionBody]);
    var functionUrl = mylib.createObjectURL(functionBlob);

    var functionBody2 = mylib.extractFunctionBody(greeter);
    var functionBlob2 = mylib.createBlob([greeter]);
    var functionUrl2 = mylib.createObjectURL(functionBlob2);

    var worker = new Worker(functionUrl);
    worker.onmessage = function(event) {
        document.getElementById("divText").innerHTML = event.data;
    }
    worker.postMessage({
                type: "init",
                content: functionUrl2
            });
</script>

目前它导致将 divText 值设置为“importScripts 成功”。

难道我做错了什么?还有另一种方法可以将函数传递给网络工作者吗?还是不可能?

4

3 回答 3

10

事实证明这种方法工作正常,我的工人只有一个错误:

var result = greeter("john");

应该

var result = greet("john");

这是有道理的——我将 greeter 变量传递给工作人员,但它没有理由知道我正在传递的对象的变量名。

于 2012-08-13T15:54:25.390 回答
5

对于那些正在寻找更通用答案的人:这是一个插件,它允许您在线程中执行 javascript 代码的任何功能。

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

将其视为“功能外包”。您将任何函数作为参数传递给插件并在回调中获得结果。您还可以“外包”对象的方法、具有依赖关系的函数、匿名函数和 lambda。

享受。

——瓦迪姆

于 2013-07-30T07:01:27.783 回答
2

是的,当然可以,我实现了

这是一个将执行通用工作者的承诺

/*
    @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("}"))
            }
        }

    })
}

通用工作文件 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)

使用它 :)

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;
    }   
}
于 2017-12-14T01:37:27.097 回答