Detect whether postMessage can send objects?

25,896

Solution 1

I found an even easier way to detect if postMessage only supports strings or if it supports other types. Simply add a custom toString-method on the object. When trying to send an object with postMessage in IE8 and IE9 they will be converted to a string with the toString-method on the object. Since browsers that support sending objects doesn't call toString we can use this to our advantage. This test is not async, so you'll get the result instantly. Haven't tested this with web-workers, but I suppose you can use the same technique.

var onlyStrings = false;
try{window.postMessage({toString:function(){onlyStrings=true;}},"*");}catch(e){}

console.log("Browser only supports postMessage with strings? " + onlyStrings);

Tested in IE8, IE9, IE10 and latest version of Chrome, Firefox, Safari and Opera: http://jsbin.com/igowoFaj/1/edit?js,console

Update: Did a BrowserScope test with many more tests and browsers. Conclusion is that it's safe to send clonable objects, arrays, numbers, pixel data and array buffers if onlyStrings is false. In theory all browsers that allow sending objects should use the structured clone algorithm, but the Android browser and Opera Mobile has quirks. The BrowserScope test result is a bit hard to read, because a 0 for send_xxx is only problematic if the browser actually has support for that type, so check supports_xxx too. If they are equal it's ok, but it's a bug if the browser has support but can't send (when onlyStrings is false).

Solution 2

I wanted to know the same thing. I created this script to detect if an object could be passed in postMessage by a simple callback to the current window. You will see IE 9 return false, IE 10 returns true.

http://jsfiddle.net/milesplit/DvqqH/

var supportsPostObject = false;

(function(){
    var callback = function(e) {
        supportsPostObject = (typeof(e.data)!='string');
    };
    (window.addEventListener) ?
        window.addEventListener('message', callback) :
        window.attachEvent('onmessage', callback);
    ('postMessage' in window) && window.postMessage({}, '*');
})();

setTimeout(function(){
   alert(supportsPostObject);
}, 0);

Solution 3

You could try to perform an action BEFORE resuming your script. You could try this:

dummy_task.js

self.onmessage = function(event) {
    self.postMessage(event.data);
};

javascript

workerSupportObject(callback);

function workerSupportObject(callback) {
    var callbackIsCalled = false; // to make sure callback isn't run twice
    var worker = new Worker('dummy_task.js'); // create a worker

    // create event
    worker.onmessage = function(event) {
        // if the value is the same as we sent, it probably works
        if(!callbackIsCalled) callback.call(null, event.data.value === 'dummy');
        callbackIsCalled = true;
    };

    try {
        // send dummy JSON data
        worker.postMessage({'value': 'dummy'});
    } catch(e) {
        // oh... an error... clearly that's a no.
        if(!callbackIsCalled) callback(null, false);

        callbackIsCalled = true;
    }
}

function callback(objectSupported) {
    console.log('Worker supports objects: ', objectSupported);
}
Share:
25,896
Stephen Simpson
Author by

Stephen Simpson

More than 20 years of Web Programming & Development with Node.js, AngularJs, MongoDb, Foundation, Lotus Domino, PHP, Dojo, jQuery, MySQL, Lotusscript, Apache & IIS, Nginx, and Wordpress. Basically, a programming language and platform polyglot. Javascript on both the server and the browser is my speciality. I started back the days of Netscape Navigator and have continued through all the iterations to ES6. Years of experience on poor performing browsers means I understand the fundamentals as well as the latest framework. Linux Server expert meaning I know how to install and configure a webserver or email system as well as front-end programme a website.

Updated on July 16, 2022

Comments

  • Stephen Simpson
    Stephen Simpson almost 2 years

    I'm looking for a neat way to detect whether postMessage in the browser supports the sending and receiving of objects or just strings. I figure that someone out there must have wrote something that does this but I have not managed to find a solution.

    I'm using postMessage to send data to/from a WebWorker. Whilst detecting whether the browser supports workers is straight-forward, detecting whether objects can be send via postMessage has proved more difficult.

    I'd like to write a simple detection function. So, if the browser supports the sending of objects to use that. If only strings are allowed I can fallback to using JSON.stringify(). I'll probably assign the function to a dojo/has test (although this is not relevant to the question/answer).

    What have other people done to solve this problem? Any advice would be great, I'm new to both WebWorkers and postMessage. Thanks in advance.

  • Stephen Simpson
    Stephen Simpson over 11 years
    Thanks, this seemed to work quite well. It's unfortunate that this cannot be done without callbacks as it voids being able to assign this to a has() function. Without the structures in place to ensure the has() is only called after availability has been tested. However, given the event based nature of what we are doing here it is probably impossible to do this without a callback. Thanks for your help.