ionic-team / ionic-framework

A powerful cross-platform UI toolkit for building native-quality iOS, Android, and Progressive Web Apps with HTML, CSS, and JavaScript.
https://ionicframework.com
MIT License
50.99k stars 13.52k forks source link

bug: webkit performance issue when using large number of css variables #22951

Open moridianmess opened 3 years ago

moridianmess commented 3 years ago

Bug Report

Ionic version:

[ ] 4.x [x] 5.x

Current behavior: This only affects real iOS devices. Tested with a 5 year old iPad and a brand new one. As more UI rich components are added to the page on iOS it gets less and less responsive, until it stops responding and the following error is seen in xCode's debugger Connection::waitForSyncReply: Timed-out while waiting for reply, which is apparently a WKWebView error message.

Expected behavior: That it behaves like Android, browser and iOS simulators

Steps to reproduce: Create a brand new blank ionic 5 app with one page that uses a loop to add components to the page.

Related code: I have created a github repo that uses the demo for ion-radio from the usage section on the component's documentation page. You can edit the number added by changing the questionIndexes variable on home.page.ts. It is currently set at 38 loops, and this produces the issue, if you drop the loop to 3, it acts as you would expect.

https://github.com/moridianmess/iOSEfficiency

Other information: This is reproducible with other ionic components, for instance 875 ion-buttons causes the waitForSyncReply error. And the UI starts becoming slow after around 50 are added.

Due to the fact the iOS simulator, Android devices and the browser do not appear to have this issue, my assumption is that this is something to do with WKWebView or the process that interacts with it.

Does anyone have any ideas?

Thanks.

Ionic info:

Ionic:

   Ionic CLI                     : 6.12.4 (/usr/local/lib/node_modules/@ionic/cli)
   Ionic Framework               : @ionic/angular 5.5.3
   @angular-devkit/build-angular : 0.1002.2
   @angular-devkit/schematics    : 10.0.8
   @angular/cli                  : 10.0.8
   @ionic/angular-toolkit        : 2.3.3

Capacitor:

   Capacitor CLI   : 2.4.2
   @capacitor/core : 2.4.6

Utility:

   cordova-res : 0.15.3
   native-run  : not installed

System:

   NodeJS : v14.15.4 (/usr/local/bin/node)
   npm    : 6.14.10
   OS     : macOS Big Sur
liamdebeasi commented 3 years ago

What version of iOS are you testing this on? I cannot reproduce this on my end.

moridianmess commented 3 years ago

14.4 on an iPad Air 2

liamdebeasi commented 3 years ago

Can you reproduce this on an iPhone, or is it only on the iPad?

moridianmess commented 3 years ago

I don't have an iPhone to test with.

liamdebeasi commented 3 years ago

Is there anything in the Xcode console prior to the "waitForSyncReply" error? I am testing on an iPad 6th gen running iOS 14.3 and cannot reproduce the performance issues described here.

moridianmess commented 3 years ago

The waitForSyncReply error does not happen in the example I have given. You will need to up the number of elements on the page to 200 to get that actual error message.

2021-02-19 15:55:17.068861+0000 App[58715:4336530] WF: _WebFilterIsActive returning: NO
APP ACTIVE
Reachable via WiFi
⚡️  [log] - Angular is running in development mode. Call enableProdMode() to enable production mode.
⚡️  To Native ->  App addListener 52772999
⚡️  WebView loaded
2021-02-19 15:55:25.539210+0000 App[58715:4336530] [IPC] Connection::waitForSyncReply: Timed-out while waiting for reply for WebPage_TouchEventSync from process 58716, id = 1

The example does show the slowness, which has no associated error message. The selection of an option takes just over a second from releasing your finger to the icon changing. When there are only 3 or 4 on the page then as soon as you release the button the icon changes. The more items you add the longer it takes to select the item. For example at 100 items it takes another half a second longer, 150 we're now taking nearly 2 seconds to show the icon, 200 get the waitForSyncReply error.

liamdebeasi commented 3 years ago

Thanks. I tested again, this time with the options but I was still unable to reproduce the issue. Can you do some additional debugging on your end to further isolate where the issue is coming from? Two things that would be good to collect:

  1. A snapshot of the "Layers" tab in Safari dev tools. Just a screenshot of both the 3D model as well as the "All Layers" side bar.
  2. A "Timeline" log. Click the "Timelines" tab and hit the red circle button in the top left. Interact with the page until you run into the performance issues you described. Once that happens, stop recording and click the "Export" button in the top right.

Attach both to a comment in this thread and I can take a closer look. Thanks!

moridianmess commented 3 years ago

The below is for 200 items causing the waitForSyncReply issue: Screenshot 2021-02-19 at 16 18 01 The timeline:

Ionic Team Edit: I commented out the timeline so I don't need to keep scrolling past it every time I open this issue :blush: -@ldebeasi

The below is for 38 items causing the slow to react issue: Screenshot 2021-02-19 at 16 26 11 The timeline:

Ionic Team Edit x2: I commented out the timeline so I don't need to keep scrolling past it every time I open this issue :blush: -@ldebeasi

Hopefully that's what you need, thanks.

liamdebeasi commented 3 years ago

Thank you! I ended up increasing the number of questionIndexes and I can reproduce the issue now. I am still investigating, but this looks like a WebKit issue. I am running the same code on iOS 14.4 and iOS 13.6 and the issue only happens in iOS 14.4.

Will post here when I have more info.

moridianmess commented 3 years ago

Cheers @liamdebeasi, I came to the conclusion is was something in WKWebView, but I'm glad you can replicate it on the same iOS version.

liamdebeasi commented 3 years ago

Ok so the issue here is that there seems to be a bug in WebKit where using Web Components with a large number of CSS Variables set on the host causes the performance issues you reported here. I can only reproduce this on iOS 14, so this seems like a fairly new bug.

I reported this to the WebKit team here: https://bugs.webkit.org/show_bug.cgi?id=222187

Typically we close related Ionic issues out whenever a fix ships in WebKit, so I will update this thread when that happens. Thanks!

moridianmess commented 3 years ago

Thanks for your timely response to this @liamdebeasi, you're a star.

liamdebeasi commented 3 years ago

Hey there,

Is this issue impacting any apps/websites you have in production right now? The WebKit folks are trying to figure out the impact of the issue so they can prioritize fixing it:

...Is it affecting some major business operation? Any information regarding how much of a wide impact this bug has will help us prioritize it.

moridianmess commented 3 years ago

Yeah, we have 5 apps in production that this affecting.

liamdebeasi commented 3 years ago

Thanks! Do you have a link to one or two of them on the app store that I can pass along?

moridianmess commented 3 years ago

I have the Google play store links:

https://play.google.com/store/apps/details?id=com.ionicframework.smartforms335372

https://play.google.com/store/apps/details?id=com.propeller_studios.contracts

https://play.google.com/store/apps/details?id=com.propeller_studios.virtualyard

https://play.google.com/store/apps/details?id=com.propeller_studios.plannedworks.financial

https://play.google.com/store/apps/details?id=com.propeller_studios.plannedworks

philmmoore commented 2 years ago

@liamdebeasi I can see that https://bugs.webkit.org/show_bug.cgi?id=222187 got marked as resolved but the issues remains open. Did this get patched in the framework? I'm seeing this in one of our apps. See the video after I navigate back, when I land on the students tab the waitForSyncReply beings to show in the Xcode console and I can no longer interact with the app.

https://user-images.githubusercontent.com/2862059/174851948-93da6760-1db4-4c2e-a4a3-ccf84ef5d749.mp4

liamdebeasi commented 2 years ago

No Ionic patch is needed for this issue. Updating to the latest version of iOS should be sufficient.

However, I will note that the WebKit patch was only a partial fix. There is an additional issue here: https://bugs.webkit.org/show_bug.cgi?id=226330 (noted at the bottom of https://bugs.webkit.org/show_bug.cgi?id=222187)

philmmoore commented 2 years ago

@liamdebeasi ok great, the simulator is running iOS 15.2 is there a particular version it should be targeting?

Is there any sort of workaround for this whilst webkit look to resolve the issue?

liamdebeasi commented 2 years ago

Unfortunately, I do not know which release of iOS this patch shipped in (there's no easy way to tell at the moment). However, the initial issue was fixed May 2021. Targeting iOS 15.2 (released December 2021) should be fine.


I am not aware of a good workaround at the moment. The fastest way to get this issue resolved is to comment on https://bugs.webkit.org/show_bug.cgi?id=226330. In particular, the WebKit team is looking to understand the severity of the issue in order to prioritize the issue. In the past, they have mentioned it is helpful to have a link to a production application that is impacted by the issue.

philmmoore commented 2 years ago

Thanks @liamdebeasi I have posted on the issue.

Is this an issue that can easily be replicated or is it down to the size of an app and its underlying structure?

I still see the issue on a physical device running the latest OS so wondering if it could be something else causing or triggering the sync problem.

I note that in my example it happens when I go back to a root view but those views are already in the DOM so must be the pseudo elements getting invalidated that kills it

liamdebeasi commented 2 years ago

It really depends on what is triggering waitForSyncReply. In the case of this thread, it is a large number of CSS variables (i.e. thousands of CSS Variables) that is causing it.

moridianmess commented 2 years ago

Is there any sort of workaround for this whilst webkit look to resolve the issue?

I implemented lazy loaded components on all our forms. I load in all components in the current viewport plus one either side. On scroll, I load in any components that enter the range. I unload components that scroll out of range and set the container div to the height of the component before unloading it. This stops the scroll bar jumping around. This is an overly complicated solution, but it's the only way I could a working iOS form with more than 15-20 components on.

ash737 commented 5 months ago

Is there any update here? I have same issue

liamdebeasi commented 5 months ago

This is a WebKit issue, so any updates will come from Apple on https://bugs.webkit.org/show_bug.cgi?id=226330. We only keep the issue open here for community visibility.