检测postMessage是否可以发送对象?

时间:2012-12-07 11:13:23

标签: javascript html5 dojo web-worker postmessage

我正在寻找一种巧妙的方法来检测浏览器中的postMessage是否支持发送和接收对象或只是字符串。我认为那里的某个人必须写了一些能做到这一点的东西,但我还没有找到解决办法。

我正在使用postMessage向/从WebWorker发送数据。检测浏览器是否支持工作人员是直截了当的,检测对象是否可以通过postMessage发送已经证明更加困难。

我想写一个简单的检测功能。因此,如果浏览器支持发送使用它的对象。如果只允许字符串,我可以回退到使用JSON.stringify()。我可能会将函数分配给dojo / has测试(尽管这与问题/答案无关)。

其他人为解决这个问题做了什么?任何建议都会很棒,我是WebWorkers和postMessage的新手。提前谢谢。

4 个答案:

答案 0 :(得分:21)

我找到了一种更简单的方法来检测postMessage是否仅支持字符串还是支持其他类型。只需在对象上添加自定义toString方法即可。当尝试在IE8和IE9中使用postMessage发送对象时,它们将在对象上使用toString-method转换为字符串。由于支持发送对象的浏览器不会调用toString,因此我们可以使用它。此测试不是异步,因此您将立即获得结果。没有对网络工作者进行测试,但我想你可以使用相同的技术。

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

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

在IE8,IE9,IE10以及Chrome,Firefox,Safari和Opera的最新版本中进行了测试: http://jsbin.com/igowoFaj/1/edit?js,console

更新:BrowserScope test有更多测试和浏览器。结论是,如果onlyStringsfalse,则发送可克隆对象,数组,数字,像素数据和数组缓冲区是安全的。理论上,所有允许发送对象的浏览器都应使用structured clone algorithm,但Android浏览器和Opera Mobile都有怪癖。 BrowserScope测试结果有点难以阅读,因为如果浏览器实际上支持该类型,则send_xxx的0只有问题,因此请检查supports_xxx。如果它们相等就没关系,但是如果浏览器有支持但是无法发送(当onlyStrings为false时),这是一个错误。

答案 1 :(得分:3)

我想知道同样的事情。我创建了这个脚本来检测是否可以通过对当前窗口的简单回调在postMessage中传递对象。您将看到IE 9返回false,IE 10返回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);

答案 2 :(得分:2)

您可以尝试在恢复脚本之前执行操作。你可以试试这个:

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

答案 3 :(得分:0)

postMessage也适用于iframe s;假设工人和框架之间的行为是相同的,你应该尝试以下或类似的东西:

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

您可能需要替换console或console.log才能看到结果,但在Chrome上,这会让我

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

当我将其保存到本地文件并打开它时。

jsfiddle版本(以及使用实际工作者的版本)留给读者练习。 :)