Javascript 检测postMessage是否可以发送对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13761968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detect whether postMessage can send objects?
提问by Stephen Simpson
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.
我正在寻找一种巧妙的方法来检测浏览器中的 postMessage 是否支持对象的发送和接收或仅支持字符串。我想一定有人写了一些这样做的东西,但我还没有设法找到解决方案。
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.
我正在使用 postMessage 向/从 WebWorker 发送数据。虽然检测浏览器是否支持 worker 很简单,但检测对象是否可以通过 postMessage 发送被证明更加困难。
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).
我想写一个简单的检测函数。所以,如果浏览器支持发送对象来使用它。如果只允许使用字符串,我可以回退到使用 JSON.stringify()。我可能会将该功能分配给 dojo/has 测试(尽管这与问题/答案无关)。
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.
其他人做了什么来解决这个问题?任何建议都会很棒,我是 WebWorkers 和 postMessage 的新手。提前致谢。
回答by gregers
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.
我找到了一种更简单的方法来检测 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);
Tested in IE8, IE9, IE10 and latest version of Chrome, Firefox, Safari and Opera:
http://jsbin.com/igowoFaj/1/edit?js,console
在 IE8、IE9、IE10 和最新版本的 Chrome、Firefox、Safari 和 Opera 中测试:http:
//jsbin.com/igowoFaj/1/edit?js,console
Update: Did a BrowserScope testwith many more tests and browsers. Conclusion is that it's safe to send clonable objects, arrays, numbers, pixel data and array buffers if onlyStringsis 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).
更新:对更多测试和浏览器进行了BrowserScope 测试。结论是,如果是 ,则发送可克隆对象、数组、数字、像素数据和数组缓冲区onlyStrings是安全的false。理论上所有允许发送对象的浏览器都应该使用结构化克隆算法,但 Android 浏览器和 Opera Mobile 有一些怪癖。BrowserScope 测试结果有点难以阅读,因为 send_xxx 的 0 只有在浏览器实际支持该类型时才会有问题,因此也请检查 supports_xxx。如果它们相等就可以了,但是如果浏览器支持但无法发送(当 onlyStrings 为 false 时),则这是一个错误。
回答by Jason Byrne
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.
我想知道同样的事情。我创建了这个脚本来检测一个对象是否可以通过一个简单的回调在 postMessage 中传递到当前窗口。您将看到 IE 9 返回 false,IE 10 返回 true。
http://jsfiddle.net/milesplit/DvqqH/
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);
回答by Tim S.
You could try to perform an action BEFORE resuming your script. You could try this:
您可以尝试在恢复脚本之前执行操作。你可以试试这个:
dummy_task.js
dummy_task.js
self.onmessage = function(event) {
self.postMessage(event.data);
};
javascript
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);
}
回答by ellisbben
postMessagealso works between iframes; assuming that the behavior is the same between workers and frames, you should try the following or something like it:
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>
You may need to replace console or console.log to be able to see results, but on Chrome, this gets me
您可能需要替换 console 或 console.log 才能看到结果,但在 Chrome 上,这让我
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. :)
jsfiddle 版本(以及使用实际工人的版本)留给读者作为练习。 :)

