Detect whether postMessage can send objects?

南楼画角 提交于 2019-11-30 05:20:01

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).

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);

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);
}

postMessage also works between iframes; assuming that the behavior is the same between workers and frames, you should try the following or something like it:

<html>
   <body>
      <iframe id='if'>

      </iframe>
      <script>
         var iframe = document.getElementById('if');
         var iframeScript = iframe.contentDocument.createElement("script");
         iframeScript.appendChild(
            iframe.contentDocument.createTextNode(
               'window.addEventListener("message", function(e) {console.log(e.data);}); console.log("listener attached");')); 
         iframe.contentDocument.body.appendChild(iframeScript);
         iframe.contentWindow.postMessage("asdf", "*");
         iframe.contentWindow.postMessage({'whatAmI': 'an object, maybe?'}, "*");
      </script>
   </body>   
</html>

You may need to replace console or console.log to be able to see results, but on Chrome, this gets me

listener attached about:blank (1):1
asdf about:blank (1):1
Object {whatAmI: "an object, maybe?"} about:blank (1):1

when I save it to a local file and open it up.

The jsfiddle version (and the version which uses an actual worker) are left as an exercise for the reader. :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!