MicrosoftEdge / WebView2Feedback

Feedback and discussions about Microsoft Edge WebView2
https://aka.ms/webview2
427 stars 51 forks source link

WriteBytesAsync with Uint8Array is slower than WebView1 counterpart. #3486

Open vagisha-nidhi195 opened 1 year ago

vagisha-nidhi195 commented 1 year ago

Description Windows.Storage.FileIO.WriteBytesAsync takes in a file and byteBuffer https://learn.microsoft.com/en-us/uwp/api/windows.storage.fileio.writebytesasync?view=winrt-22621. With WebView2, passing Uint8Array(data) as unknown as number[] results in Interface not supported error.

Windows.Storage.FileIO.WriteBytesAsync(file, new Uint8Array(data) as unknown as number[])

It works when you pass a shallow copy of the object using, but we should be able to directly pass the Uint8Array as it was supported in webview1. Array slicing adds additional delay to write operations.

Windows.Storage.FileIO.WriteBytesAsync(file, Array.prototype.slice.call(new Uint8Array(data)) as unknown as number[])

Version SDK: 1.0.1777-prerelease Framework: UWP/WinRT OS: Win10

Repro Steps

  1. Create a WinRT on UWP project with WebView2 following https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/winrt-from-js?tabs=winui2%2Cwinrtcsharp
  2. Run the app. Open the DevTools console and try the following:
Windows.Storage.FileIO.WriteBytesAsync(file, new Uint8Array(data) as unknown as number[])

Output

Interface not supported

Screenshots

Additional context This works as it is in webview1, regressed in webview2

AB#45973938

novac42 commented 1 year ago

Thanks for reporting the issue. I've assigned this to a dev who can help follow up on this.

david-risney commented 1 year ago

I've opened a tracking bug for this. If it worked with the previous WebView1's WinRT projection we should look at supporting it for WebView2 - thanks!

emre-ozgu commented 1 year ago

Adding on to this, passing a plain array using Array.prototype.slice.call(new Uint8Array(data) or Array.from(new Uint8Array(data) seems to make the Windows.Storage.FileIO.WriteBytesAsync operation take much longer in general compared to WebView1, outside of the conversion as well. This especially makes writing larger files (e.g. ~15MB) infeasible on WebView2.

WebView1 - JavaScript Code:

let timeMs = Date.now();
Windows.Storage.FileIO.writeBytesAsync(file, new Uint8Array(data))
    .then(() => console.log(`WriteBytesAsync took ${Date.now() - timeMs}ms - Data Size: ${data.byteLength / 1000 / 1000}MB`));

Output 1:

WriteBytesAsync took 31ms - Data Size: 0.53288MB

Output 2:

WriteBytesAsync took 114ms - Data Size: 18.551616000000002MB

WebView2 - JavaScript Code:

let timeMs = Date.now();
const dataArray = Array.from(new Uint8Array(data));
console.log(`Array.from took ${Date.now() - timeMs}ms - Data Size: ${data.byteLength / 1000 / 1000}MB`);

timeMs = Date.now();
Windows.Storage.FileIO.writeBytesAsync(file, dataArray)
    .then(() => console.log(`WriteBytesAsync took ${Date.now() - timeMs}ms - Data Size: ${data.byteLength / 1000 / 1000}MB`));

Output 1:

Array.from took 34ms - Data Size: 0.53288MB
WriteBytesAsync took 2098ms - Data Size: 0.53288MB

Output 2:

Array.from took 800ms - Data Size: 18.551616000000003MB
WriteBytesAsync took 66655ms - Data Size: 18.551616000000003MB
vagisha-nidhi195 commented 1 year ago

@david-risney Any update on this one? We are really looking forward to getting the read/write bytes issues fixed.

david-risney commented 1 year ago

Apologies, no good update yet.

The WinRT API will be slow in this case at least because the byte array is in JS and the WinRT API is in the host app. The call to write the bytes will serialize all the bytes in the JS byte array, send the request to the host app, deserialize it into a native byte array and then actually call the WinRT API in the host app process.

If you can keep the bytes in a WinRT object rather than a JS object then we won't have to serialize all bytes. I'm not sure if that's practical for this scenario.

Alternatively perhaps instead of calling into the WinRT API to write the bytes you could use the shared buffer API to get the bytes to the native host app side without needing to serialize the byte array.

yildirimcagri-msft commented 2 months ago

Hi again, if the idea is to be able to read/write to some file in web content in WebView2 directly, you can now use the CoreWebView2.PostWebMessageAsJsonWithAdditionalObjects to share a FileSystemHandle directly to the web content from the app. Even a working WinRT API approach will not be as performant due to reasons stated above.