8

我正在寻找一种简洁的方法来检测浏览器中的 postMessage 是否支持对象的发送和接收或仅支持字符串。我认为那里一定有人写了一些东西来做到这一点,但我还没有设法找到解决方案。

我正在使用 postMessage 向/从 WebWorker 发送数据。虽然检测浏览器是否支持 worker 很简单,但检测对象是否可以通过 postMessage 发送被证明更加困难。

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

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

4

4 回答 4

22

我发现了一种更简单的方法来检测 postMessage 是否仅支持字符串或是否支持其他类型。只需在对象上添加一个自定义 toString 方法。当尝试在 IE8 和 IE9 中使用 postMessage 发送对象时,它们将使用对象上的 toString 方法转换为字符串。由于支持发送对象的浏览器不调用 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 测试。结论是发送可克隆对象、数组、数字、像素数据和数组缓冲区onlyStrings是安全的false。理论上所有允许发送对象的浏览器都应该使用结构化克隆算法,但是 Android 浏览器和 Opera Mobile 有一些怪癖。BrowserScope 测试结果有点难以阅读,因为 send_xxx 的 0 只有在浏览器确实支持该类型时才会有问题,所以也要检查 supports_xxx。如果它们相等,则可以,但如果浏览器支持但无法发送(当 onlyStrings 为 false 时),则这是一个错误。

于 2013-12-23T12:11:00.137 回答
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);
于 2013-03-09T06:36:36.380 回答
3

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

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);
}
于 2012-12-07T11:28:10.093 回答
0

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

<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 版本(以及使用实际工作人员的版本)留给读者作为练习。:)

于 2013-01-08T18:39:00.970 回答