最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Pass object by reference fromto webworker - Stack Overflow

programmeradmin1浏览0评论

Is it possible passing an object from/to webWorker from/to main thread by reference? I have read here information about transferable objects.

Chrome 13 introduced sending ArrayBuffers to/from a Web Worker using an algorithm called structured cloning. This allowed the postMessage() API to accept messages that were not just strings, but complex types like File, Blob, ArrayBuffer, and JSON objects. Structured cloning is also supported in later versions of Firefox.

I just want to pass information, not object with methods. Just something like this (but with a lot of information, a few MB, so that main thread does not have to receive a copy of the object):

var test = {
    some: "data"
}

Is it possible passing an object from/to webWorker from/to main thread by reference? I have read here information about transferable objects.

Chrome 13 introduced sending ArrayBuffers to/from a Web Worker using an algorithm called structured cloning. This allowed the postMessage() API to accept messages that were not just strings, but complex types like File, Blob, ArrayBuffer, and JSON objects. Structured cloning is also supported in later versions of Firefox.

I just want to pass information, not object with methods. Just something like this (but with a lot of information, a few MB, so that main thread does not have to receive a copy of the object):

var test = {
    some: "data"
}
Share Improve this question asked Nov 5, 2015 at 12:49 javifmjavifm 7054 gold badges9 silver badges22 bronze badges 1
  • Can you clarify why the method at transferable objects doesn't doesn't do what you want? Is it that you want both worker and main thread to have access to the exact same object in memory at the same time? – Michal Charemza Commented Nov 9, 2015 at 8:21
Add a comment  | 

3 Answers 3

Reset to default 6

Once you have some data in an object (this: {bla:666, color:"red"}) you will have to copy it and there is no way to avoid it. The reason is, that you don't have control over the memory object is stored in, so you can't transfer it. The only memory that can be transferred is memory allocated for transferable objects - typed arrays.

Therefore if you need some data transferred, you must think in advance and use the transferable interface. Also keep in mind that even when object is copied, the transfer speed is very fast.

I wrote a library that converts object to binary data (therefore transferable), but it isn't faster than native transfer, it's way slower actually. The only advantage is that it allows me to transfer unsupported data types (eg. Function).

There Is An Array 2nd Argument To postMessage

Actually yes, it is possible in, (surprise, Surprise!) Chrome 17+ and Firefox 18+ for certain objects (see here).

// Create a 32MB "file" and fill it.
var uInt8Array = new Uint8Array(1024 * 1024 * 32); // 32MB
for (var i = 0; i < uInt8Array.length; ++i) {
  uInt8Array[i] = i;
}
worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);

You can also apply this to strings by converting the string to and from an array buffer using FastestSmallestTextEncoderDecoder as shown below.

//inside the worker
var encoderInst = new TextEncoder;
function post_string(the_string){
    var my_array_buffer = encoderInst.encode(the_string).buffer;
    postMessage( my_array_buffer, [my_array_buffer] );
}

Then, to read the arraybuffer as a string:

// var workerInstance = new Worker("/path/to/file.js");
var decoderInst = new TextDecoder;
workerInstance.onmessage = function decode_buffer(evt){
    var buffer = evt.data;
    var str = decoderInst.decode(buffer);
    console.log("From worker: " + str);
    return str;
}

Here is a small interactive example of using a Worker to increment each letter of a string.

var incrementWorker = new Worker("data:text/javascript;base64,"+btoa(function(){
    // inside the worker
    importScripts("https://dl.dropboxusercontent.com/s/r55397ld512etib/Encode" +
        "rDecoderTogether.min.js?dl=0");
    const decoderInst = new TextDecoder;
    
    self.onmessage = function(evt){
        const u8Array = new Uint8Array(evt.data);
        for (var i=0, len=u8Array.length|0; i<len; i=i+1|0) {
            ++u8Array[i];
        }
        postMessage(decoderInst.decode(u8Array));
    };
} .toString().slice("function(){".length, -"}".length)));

const inputElement = document.getElementById("input");
const encoderInst = new TextEncoder;

(inputElement.oninput = function() {
    const buffer = encoderInst.encode(inputElement.value).buffer;
    incrementWorker.postMessage(buffer, [buffer]); // pass happens HERE
})();

incrementWorker.onmessage = function(evt){
    document.getElementById("output").value = evt.data;
};
<script src="https://dl.dropboxusercontent.com/s/r55397ld512etib/EncoderDecoderTogether.min.js?dl=0" type="text/javascript"></script>
Before: <input id="input" type="text" value="abc123 foobar" /><br />
After:&nbsp;&nbsp; <input id="output" type="text" readonly="" />


Sources: Google Developers and MDN

It is not possible. You have to send the object, update it in the worker and then return the updated version to the main thread.

If you want to pass an object just with information, you only need to pass your object as a string

myWorker.postMessage(JSON.stringify(myObject)); 

parse the object inside your worker

JSON.parse(myObject)

and finally return your updated object to the main thread. Take a look also to ParallelJs that is library to work easier with web-workers

发布评论

评论列表(0)

  1. 暂无评论