Performance Q&A guide

I’m consistently getting under 4 seconds, and sometimes under 3.

You could compress your images. That background image is 1.2MB…can get that down to 350k or less with minimal loss.

2 Likes

Thanks for checking it out. On my device to load time varies between 4-9 seconds depending on the internet speed (glas fiber at work and still quite fast internet at home)

This is what different tests show us:
https://www.webpagetest.org/result/170703_DE_QRT/
https://gtmetrix.com/reports/www.pflegetiger.de/EyIwdtCg
https://developers.google.com/speed/pagespeed/insights/?hl=de&url=www.pflegetiger.de&tab=mobile

Google Analytics points out that we have a latency problem, i.e. we are receiving more clicks on campaigns than we are receiving visitors.

Besides the other tests, the Google results matter a lot for us, as page load time influences the quality score of the page.

Most of these things are outside my wheelhouse, but regarding the two “F” ratings, this is what I found…

Defer parsing of Javascript - I think this is native to the bubble architecture, so you are stuck with this.

Landing page redirects - Can this be done server side? I don’t know @emmanuel

I have seen other Gmetrix reports from Bubblers where the elements that you have as D’s, they have as A’s (Keep Alive; browser caching; optimize images), so it would seem to be fixable.

Another good performance testing tool is Pingdom. I have noticed that all bubble sites have (at least) around 600+ KB of JavaScript (and more, if they include other libraries, like Stripe, etc.). I am assuming that this 600+ KB is comprised of Node.js and Coffee Script… my question to the @Bubble team and @josh is whether this can be optimized at all?

Also, can any of the below Pingdom performance insights be addressed?

Thanks!

2 Likes

From a database/ data structure perspective, can someone explain to me why ‘Do a search for’ is so much quicker than referencing a Thing’s list of things?

I would assume the database just needs to refer to the current Thing and retrieve a connected list, where with Search for it searches through everything first.
I built most of my app around the concept of creating one main Thing with al kinds of other Things connected (Users, Invoices etc).
So what I always do in a workflow is add the secondary thing (as a list) to the main Thing. But because retrieving this so slow, I wonder if I should even do this.

The difference is enormous as you can see below.

This search box result retrieves a list of approx 300 items.

Data structure: Job Thing has Inventory Thing which has a List of Inventory Items

Left: Do a search for Inventory items with constraint of ‘Inventory is searchbox Job’s Inventory’
Right: Searchbox Job’s Inventory’s Inventory Items

3 Likes

“Loading” happens in two stages:

-Sending the code for the elements (ie, basically everything you fill out in the property panel in the editor). Yes, we do need to send the code for popups on page load.

-Executing any queries that fetch dynamic data. Ie, when you do a search, actually performing that search. Here, we don’t do this until the popup becomes visible.


Thanks to everyone helping debug www.pflegetiger.de. Re:

Yeah, it’s part of the core Bubble framework. It’s not going to go to zero any time soon, but it’s definitely shrinkable. We periodically audit the size of the code we’re sending over and cut unnecessary things to keep the size down; we’re probably overdue for another audit (the last one was over a year ago I think!), so I’ve added that to our project list, though no promises on the timing.

I’m talking off the top of my head, so no promises that this is correct, but what I think is going on is that right now to display the list of inventory things, we have to load all 300 items, whereas to do the search, we just need to load enough items to fill the repeating groups cells that are currently visible. We’re working on a project to optimize this (as part of an overhaul of our database query planning engine). Another factor is that we have to load each of the 300 items one-by-one, whereas the search we do as a single database query: we aren’t working on this right now, but it’s on our backlog of projects.

7 Likes

Thanks Josh… I should have asked, is that JavaScript cached after the initial page load? It is, right?

Yes, we tell the browser to cache it, so subsequent page loads should be faster. Also, we separate the javascript out into generic javascript that runs on every bubble app, and specific javascript for the current page, so that the generic javascript can be cached even between different bubble apps (which means the more people who use bubble, the faster apps will load!)

6 Likes

@Josh I have a performance question regarding setting Custom States. Is it more efficient to set multiple Custom States on a single element or single Custom States on many elements? Thanks!

Hello,
I have one more question: what happens if two workflows concurrently modify the same field of the same object (for instance to increase a number by 1) ?
Do you run workflows in sequences or is it parallelized (multi-threaded) in some way ?
If it is multi-threaded, do you have kind of “locks” that prevent an action from modifying a field if another user is already modifying it ? If so, does it happen at action or workflow level ? (ie, between two actions of the same worfklow, can we assume that all used objects have not been modified by another user ?)

Thanks !

Workflows run from the same web browser session are run in sequence to avoid two workflows modifying the same field (we run them in parallel if it’s safe to do so). Unfortunately, we don’t have good controls / locks for two workflows run by different users or browsers, so you can get issues if two different users try to add one to the same number at the same time. That’s on our to-do list to build, since it would make life easier to be able to offer strong guarantees about what will happen in those cases.

1 Like

@josh thanks for all the great info in this thread. It has been really helpful.
Is there a simple way to add the loading icon to the blank white page similar to the bubble work environment in the attached photo? It is so much better than users staring at a blank white page and seems like it should be easy to do.

4 Likes

Thanks for the answer, i am looking forward to it!

@josh Am I right to assume that the searches used on the page are being updated as the workflows run, so it’s possible for a reference in a workflow to suddenly shift to a different thing mid-workflow?

Like, if I have ReusableElementA in cell 3 of a Repeating Group. The Repeating Group’s list comes from a search for Thing1 that meet certain criteria. If I use a workflow to start making changes to the Thing1row5 of cell 3, and part-way through those changes Thing1row5 no longer matches the criteria of the Repeating Group’s list, then the list will update and a different Thing1 will move up to cell 3. That would mean that the references to “ReusableElementA’s Thing1” would switch mid-workflow.

No, we try to freeze a “state of the universe” at the beginning of a workflow execution, and only reflect changes when the workflow explicitly modifies something. Things like a cell in a repeating group showing a different thing we don’t count as an explicit change. That said, our rules for how exactly that works aren’t great: they’re pretty complicated (I sometimes have to read the actual Bubble source code to predict how a particular situation will play out), and they don’t handle interactions between workflows well (if two different users modify the same data at the same time, the end result might ignore the changes made by one of the users), so this is fairly high on our todo list to overhaul: I’d like to be in a place where we have a clear, easily understandable set of guarantees we can make about how data will behave.

2 Likes

@josh is Bubble smart enough to grab data delivered for another element rather than run the search again?

Like if I have a Repeating Group that loads a list of thing-A, and each thing-A has a field with thing-B, so each cell needs to go get the right thing-B for each cell. Am I right in thinking that the call for each thing-B happens after the list of thing-As is loaded?

But, what if I’ve already delivered a bunch of thing-Bs to another element on the page? Will Bubble know that it doesn’t have to go all the way back to the server to get the thing-B?

Could you also explain what happens when we call “repeating group A’s List of Items:count” ? Is that optimized in some way even if the repeating group is not showing all data ?

Also, what happens if the app shutdowns during a workflow for instance because reach too much server capacity usage (error 400) ? DO we obtain a half completed workflow ?

1 Like

Great thread. Our app pulls several images from multiple cameras, and loading each image is a bit slow (.5~1s) but once the image is loaded the first time, it’s cached and loads much faster on subsequent views. How could we cache all of these images for the user when the page is loaded? Would this be a good idea or might it hurt more than help?

Here’s our demo: https://app.barnowl.tech/demo

Note: if you click the camera name in the slideshow (CAM1/CAM2 etc), I have a popup of all images belonging to that camera. As you can see, once they all download, the slideshow is extremely fast, but only for that camera’s images.

Any other optimization advice would be hugely appreciated, thanks again!

1 Like

I made a 1x1 pixel repeating group on each camera which downloads and caches all of its images. Simple fix and the app is now lightning fast.

EDIT: It’s actually lightning fast on desktop, but still pretty slow on mobile as if it’s not caching the images.

Try it yourself, anything I could do about this? Thanks

1 Like

Next to in-app performance enhancements, I’d like to reboot the server location question again. I know the choice of server location is currently not an option in non-dedicated plans, but I really hope you will consider this in the very near future as I’d rather stay on a non-dedicated plan that keeps more money in Bubble’s pocket than to go dedicated.

I’m curious to learn 2 things:

  1. Do the differences in download speed between the Oregon server and the Frankfurt server justify going dedicated?
  2. What are other users experiencing connecting to these servers (what is normal?)

I did the following network tests:

  1. Kiev - Oregon server http://cloudharmony.com/speedtest-for-aws:ec2-us-west-2
  2. Kiev - Frankfurt server http://cloudharmony.com/speedtest-for-aws:ec2-eu-central-1
  3. Amsterdam - Oregon server http://cloudharmony.com/speedtest-for-aws:ec2-us-west-2
  4. Amsterdam - Frankfurt server http://cloudharmony.com/speedtest-for-aws:ec2-eu-central-1

Results:

1. Kiev - Oregon
Down 4 threads
1,28
Down 2 threads
3.09
Latency
397

2. Kiev - Frankfurt
Down 4 threads
9.79
Down 2 threads
35.17
Latency
97

3. Amsterdam - Oregon
Down 4 threads
1,62
Down 2 threads
13.44
Latency
379

4. Amsterdam - Frankfurt
Down 4 threads
25,56
Down 2 threads
93,23
Latency
34,5