2012-12-07 18 views
5

Ich bin auf der Suche nach einem sauberen Weg zu erkennen, ob PostMessage im Browser das Senden und Empfangen von Objekten oder nur Strings unterstützt. Ich denke, dass jemand da draußen etwas geschrieben haben muss, das das tut, aber ich habe es nicht geschafft, eine Lösung zu finden.Ermitteln, ob PostMessage Objekte senden kann?

Ich benutze postMessage, um Daten an/von einem WebWorker zu senden. Während der Erkennung, ob der Browser Arbeiter unterstützt, ist es einfach, festzustellen, ob Objekte per PostMessage gesendet werden können.

Ich möchte eine einfache Erkennungsfunktion schreiben. Also, wenn der Browser das Senden von Objekten unterstützt, um das zu verwenden. Wenn nur Strings erlaubt sind, kann ich auf die Verwendung von JSON.stringify() zurückgreifen. Ich werde die Funktion wahrscheinlich einem dojo/has-Test zuweisen (obwohl das für die Frage/Antwort nicht relevant ist).

Was haben andere Leute getan, um dieses Problem zu lösen? Jeder Rat wäre toll, ich bin neu in WebWorkers und PostMessage. Danke im Voraus.

+0

Stumme Frage von mir - können Sie 'postMessage' in das gleiche Fenster? – Ian

+0

@Ian ... was? Ein WebWorker ist eine Klasse zum Erstellen von (Pseudo-) Threads. Sie können grundsätzlich eine externe Javascript-Datei ausführen, während das Javascript auf dieser Seite weiterhin fehlerfrei läuft. Mit 'postMessage' können Sie mit diesem Thread kommunizieren. Es hat überhaupt nichts mit verschiedenen Fenstern zu tun. –

+0

Ihr erster Satz spricht über das Senden von Nachrichten mit 'postMessage'. Ich schaue 'postMessage' nach und es geht darum, Nachrichten an andere Fenster zu senden (so wie ich mich erinnere). Wenn Sie die Tatsache ignorieren, dass Sie mit Web Workers sprechen, warum würden Sie dann nicht einfach einen Testanruf starten? Ich nehme an, dass ihre Kommunikation anders ist, aber wenn Sie einen Listener im aktuellen Fenster für "onmessage" einrichten und '{}' übergeben, überprüfen Sie einfach den 'typeof', um zu sehen, ob es ein Objekt und keine Zeichenfolge ist . – Ian

Antwort

18

fand ich eine noch einfachere Art und Weise nur zu erkennen, wenn Strings unterstützt postmessage oder wenn es andere Typen unterstützt. Fügen Sie einfach eine benutzerdefinierte toString-Methode für das Objekt hinzu. Wenn Sie versuchen, ein Objekt mit postMessage in IE8 und IE9 zu senden, werden sie in eine Zeichenfolge mit der toString-Methode für das Objekt konvertiert. Da Browser, die das Senden von Objekten unterstützen, toString nicht aufrufen, können wir dies zu unserem Vorteil nutzen. Dieser Test ist nicht asynchron, sodass Sie sofort das Ergebnis erhalten. Ich habe das nicht mit Web-Mitarbeitern getestet, aber ich nehme an, Sie können dieselbe Technik verwenden.

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

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

Getestet in IE8, IE9, IE10 und neueste Version von Chrome, Firefox, Safari und Opera: http://jsbin.com/igowoFaj/1/edit?js,console

Update: Hat ein BrowserScope test mit vielen weiteren Tests und Browsern. Schlussfolgerung ist, dass es sicher ist, klonbare Objekte, Arrays, Zahlen, Pixeldaten und Array-Puffer zu senden, wenn onlyStringsfalse ist. In der Theorie sollten alle Browser, die das Senden von Objekten erlauben, die structured clone algorithm verwenden, aber der Android-Browser und Opera Mobile hat Macken. Das BrowserScope-Testergebnis ist ein bisschen schwer zu lesen, da eine 0 für send_xxx nur dann problematisch ist, wenn der Browser tatsächlich Unterstützung für diesen Typ hat, also überprüfe auch supports_xxx. Wenn sie gleich sind, ist es in Ordnung, aber es ist ein Fehler, wenn der Browser Unterstützung hat, aber nicht senden kann (wenn nur Strings falsch ist).

2

Sie könnten versuchen, eine Aktion auszuführen, bevor Sie Ihr Skript fortsetzen. Man könnte dies versuchen:

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

Danke, das schien recht gut zu funktionieren. Es ist bedauerlich, dass dies ohne Rückrufe nicht möglich ist, da es nicht möglich ist, dies einer has() -Funktion zuzuweisen. Ohne die vorhandenen Strukturen zu gewährleisten, wird das has() erst aufgerufen, nachdem die Verfügbarkeit getestet wurde. Angesichts der ereignisbasierten Natur dessen, was wir hier tun, ist es jedoch wahrscheinlich unmöglich, dies ohne einen Rückruf zu tun. Danke für Ihre Hilfe. –

0

postMessage auch zwischen iframe s arbeitet; unter der Annahme, dass das Verhalten der Arbeitnehmer und Rahmen gleich ist, sollten Sie die folgende oder etwas ähnliches versuchen:

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

Sie müssen Konsole oder console.log ersetzen können in der Lage sein, Ergebnisse zu sehen, aber auf Chrome, dies bringt mir

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

, wenn ich es in einer lokalen Datei speichern und öffnen sie es.

Die jsfiddle-Version (und die Version, die einen tatsächlichen Arbeiter verwendet) sind als Übung für den Leser übrig. :)

3

Ich wollte das Gleiche wissen. Ich habe dieses Skript erstellt, um festzustellen, ob ein Objekt in postMessage durch einen einfachen Rückruf an das aktuelle Fenster übergeben werden konnte. Sie sehen, dass IE 9 false zurückgibt, IE 10 gibt true zurück.

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