我正在寻找一种巧妙的方法来检测浏览器中的postMessage是否支持发送和接收对象或只是字符串。我认为那里的某个人必须写了一些能做到这一点的东西,但我还没有找到解决办法。
我正在使用postMessage向/从WebWorker发送数据。检测浏览器是否支持工作人员是直截了当的,检测对象是否可以通过postMessage发送已经证明更加困难。
我想写一个简单的检测功能。因此,如果浏览器支持发送使用它的对象。如果只允许字符串,我可以回退到使用JSON.stringify()。我可能会将函数分配给dojo / has测试(尽管这与问题/答案无关)。
其他人为解决这个问题做了什么?任何建议都会很棒,我是WebWorkers和postMessage的新手。提前谢谢。
答案 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有更多测试和浏览器。结论是,如果onlyStrings
为false
,则发送可克隆对象,数组,数字,像素数据和数组缓冲区是安全的。理论上,所有允许发送对象的浏览器都应使用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版本(以及使用实际工作者的版本)留给读者练习。 :)