wordpress-mobile / gutenberg-mobile

Mobile version of Gutenberg - native iOS and Android
GNU General Public License v2.0
241 stars 55 forks source link

Long delay when saving a post #6696

Closed fluiddot closed 3 months ago

fluiddot commented 6 months ago

Similar issue: https://github.com/WordPress/gutenberg/issues/55386

Describe the bug

When saving a post, both when closing the editor and tapping on the Update button, it makes the app freeze for several seconds until it responds and saves the post. Seems it only happens depending on the post content, as far as I tested, the more images uploaded to the post the slowest it goes. After testing with multiple devices, I noticed that the delay can only be reproduced in the device that uploaded the images. If I open the same post on another device, the delay is not experienced.

To Reproduce

  1. Create a post.
  2. Add a Gallery block and insert multiple images.
  3. Wait until all uploads finish.
  4. Close the editor and save the post.
  5. Observe that it takes extra seconds for the editor to close.
  6. Re-open the post.
  7. Add more images.
  8. Repeat steps 3, 4.
  9. Observe that it takes even more time for the editor to close.

Expected behavior The editor should save the post and close the editor quickly.

Screenshots

Device that uploaded images Other device

Smartphone (please complete the following information):

Additional context Seems it's not a regression as I managed to reproduce this issue in older versions:

SiobhyB commented 6 months ago

The user in 7651806-zen appears to be running into this issue. They noted they've used the app for years but only began to run into issues around mid-January. I'm not certain why this would be, as their posts prior to January were also media-heavy, but potentially related to poorer WiFi connection while travelling.

fluiddot commented 6 months ago

As far as I investigated, the issue seems related to the block processors executed for each media associated to the post when saving (reference 1, reference 2). I haven't narrowed down yet if the culprit is a specific preprocessor, I'll share more details after finishing the investigations.

fluiddot commented 6 months ago

Block processing benchmark

I benchmarked the function updateReferences that is invoked before saving the post (reference). This function is the one that uses the block processors to ensure that the media referenced in the post content is properly formed. For the test, I used a post with 2 Gallery blocks and 18 Image blocks (included in the Gallery blocks):

Media Item 1: Duration of updating references: 0.19202925 seconds

Media Item 2: Duration of updating references: 0.175285958 seconds

...

Media Item 18: Duration of updating references: 0.173225209 seconds

Total duration of processing media (18 media items): 3.128310333 seconds

As you can see, each media item takes around 175 ms to be processed. This is a very long duration, especially considering that posts might have several media items. The total time is above 3 seconds, which is aligned with the issue shared.

Delay estimations

One of the main problems is that the duration grows linearly, the more media items the longer the delay. Here's an estimation of the delay in saving post durations based on the number of media items:

A delay of one second is high but may be unnoticeable by users. However, beyond that value, I think the experience is subpar.

Potential solution

I profiled the editor using Xcode instruments and confirmed that the delay is caused by using NSRegularExpression. I presume we could improve and optimize the block processing, but still, I think relying on regular expressions to parse the HTML content will always be a bottleneck. I checked the approach we use on Android and saw that the HTML is parsed using an HTML parser library (code reference) instead of regular expressions. I haven't benchmarked Android but since the issue can't be reproduced, I understand that using a parsing library is more optimal.

That said, I propose using an HTML parser like SwiftSoup. However, I'd like to note that this approach implies refactoring all the processors.