diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp
index 1c867540be6..f1ec448d71b 100644
--- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp
+++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp
@@ -221,6 +221,11 @@ void EventLoop::queue_task_to_update_the_rendering()
// 2. Set eventLoop's last render opportunity time to the unsafe shared current time.
m_last_render_opportunity_time = HighResolutionTime::unsafe_shared_current_time();
+ // OPTIMIZATION: If there are already rendering tasks in the queue, we don't need to queue another one.
+ if (m_task_queue->has_rendering_tasks()) {
+ return;
+ }
+
// 3. For each navigable that has a rendering opportunity, queue a global task on the rendering task source given navigable's active window to update the rendering:
for (auto& navigable : all_navigables()) {
if (!navigable->is_traversable())
diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp
index 28365d38c7d..5e82c32645f 100644
--- a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp
+++ b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp
@@ -88,4 +88,13 @@ Task const* TaskQueue::last_added_task() const
return m_tasks.last();
}
+bool TaskQueue::has_rendering_tasks() const
+{
+ for (auto const& task : m_tasks) {
+ if (task->source() == Task::Source::Rendering)
+ return true;
+ }
+ return false;
+}
+
}
diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h
index 3acd2f195c3..940d5efd9c8 100644
--- a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h
+++ b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h
@@ -23,6 +23,7 @@ public:
bool is_empty() const { return m_tasks.is_empty(); }
bool has_runnable_tasks() const;
+ bool has_rendering_tasks() const;
void add(JS::NonnullGCPtr);
JS::GCPtr take_first_runnable();