WebView postMessage with ArrayBuffer terribly slow

I am porting a complex web app to a Photoshop plugin. Naturally, I am using a WebView to host the web content and using postMessage to communicate back and forth with the UXP host.

The plugin exchanges large arrayBuffers between the UXP host and the WebView very often. Unfortunately, unlike iframe postMessage which leaves ArrayBuffers intact and transfers them as is, the WebView postMessage serializes the ArrayBuffer to an empty object.

To get around this I tried converting my ArrayBuffer to a string or an array and passing that via postMessage instead.
This works but is incredibly slow. On my Windows machine an 80MB ArrayBuffer (a typical PSD file) takes 15 seconds to transfer.
WebView.postMessage currently only accepts strings and objects (stringifies to JSON and deserializes back to object on receiving end).

Would it be possible for postMessage to also accept ArrayBuffers and pass them as is? Not having to serialize and deserialize the ArrayBuffer would likely speed up data transfer a lot. I think this is related to the third postMessage parameter transfer which the docs state is " Optional and not functional yet . Will be enabled in future release".

Any ETA on this?

postMessage of ArrayBuffers to an iframe is extremely fast. Would it be possible to achieve that performance for UXP WebView?

Relevant resources:
https://developer.adobe.com/photoshop/uxp/2022/uxp-api/reference-js/Global%20Members/HTML%20Elements/HTMLWebViewElement/#postmessagemessage-targetorigin-transfer

1 Like

@lucadalli
Thank you for your great suggestion.
Your request has been registered as a backlog.

3 Likes

@lucadalli
I’ve tested WebView postMessage on my Windows machine.
(CPU is AMD Ryzen™ 9 5950X)
Passing a long string object which contains (62 * 1024 * 1024) characters, which is 124 MB in JS, takes approximately 1.3 second. (1.3 is the average of 100 times trials).

ArrayBuffers or any binaries could be sent with btoa() and then a receiver could revert it back to binaries with atob(). (UXP supports both btoa and atob).

1 Like

Is shared memory space impossible to do?

1 Like

Could you help me on how to succesfully communicate between the plugin and the WebView? I cannot make it to work with the documentation I saw in the site:

https://developer.adobe.com/photoshop/uxp/2022/uxp-api/reference-js/Global%20Members/HTML%20Elements/HTMLWebViewElement/

I literally copy and paste the code within my main.js file but it gives me an error that the window.uxpHost is undefined.

Plugin needs a permission ‘enableMessageBridge’ in the manifest.
For example,

{
“manifestVersion”: 5,
“requiredPermissions”: {
“webview”: {
“allow”: “yes”,
“domains”: [ “https://.adobe.com", "https://.google.com”],
// enableMessageBridge can use either of these data “localAndRemote” | “localOnly” | “no”
“enableMessageBridge”: “localAndRemote”
}
}
}

Thanks @mykim , even though I already had the code you pasted, I found what my problem was. I was trying to access window.uxpHost through the browser ( for testing ) but when I fire it from the UXP webview the window.uxpHost do exists.

Thanks for your help !

@mykim do you have an example of how to do this send/receive? I have tried but not had luck sending a PSD file via the method you described. Most likely it is user error on my part in decoding the data.

I’ve tested WebView postMessage on my Windows machine.
(CPU is AMD Ryzen™ 9 5950X)
Passing a long string object which contains (62 * 1024 * 1024) characters, which is 124 MB in JS, takes approximately 1.3 second. (1.3 is the average of 100 times trials).

ArrayBuffers or any binaries could be sent with btoa() and then a receiver could revert it back to binaries with atob(). (UXP supports both btoa and atob).

@mykim This is not a fair test.
Firstly, this is a $500 CPU. It’s like going to the track with a supercar and assuming the same power from the typical car on the road.

Secondly, in your test you are only measuring how long it takes to transfer a long string. My intention is to send and receive an ArrayBuffer, meaning that your test must include the serialization of an ArrayBuffer to a string and the deserialization back into an ArrayBuffer on the receiving end.

1 Like

What is the time increase compared to size increase? Is it linear growth? Or exponential? If the second is the case you could split that into chunks.

@JasonM
I’ve attached a sample plugin. WebView content (webview.html) sends a file to Plugin with some binary to string conversion.
The sample plugin won’t work as the latest release UXP does not support loading local html.
Please just have a look at the source code as a reference.

@lucadalli
I did test it again with the attached sample plugin. You are right, it takes 10+ seconds to send 65MB file to plugin. As uxpHost.postMessage() supports only string data, it requires to base64 encoding the array buffer, which grows up to 83MB, and sending the encoded 83MB string though uxpHost.postMessage(). I agree with you that if postMessage supports arraybuffer, it will be very effective in transmitting large byte arrays. It would be worth investigating the feature.

uxp.webview.postmessage.zip (12.5 KB)

2 Likes

Thanks for the example, that is pretty close to what I am currently doing, but I was hoping you had a faster way.

@mykim thanks for investigating further! Glad we arrived at the same result.
We think that being able to send ArrayBuffers would open up a migration path to UXP for CES extensions that are currently reliant on using Node as a WebSocket server to transfer large ArrayBuffers.