performance: sort debouncing

This commit is contained in:
Salikh Gurgenidze
2026-01-23 22:29:29 +04:00
parent 7ae8e26f74
commit 2263fd53c6
3 changed files with 135 additions and 66 deletions
+1
View File
@@ -1625,6 +1625,7 @@ function SortEngine:ExecuteSort(sortFunction, analyzeFunction, updateFrame, sort
if noProgressPasses >= 5 then if noProgressPasses >= 5 then
addon:DebugSort("%s sort stopped due to no progress after %d passes (items remaining: %d/%d)", addon:DebugSort("%s sort stopped due to no progress after %d passes (items remaining: %d/%d)",
sortType, passCount, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems) sortType, passCount, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems)
-- Final update -- Final update
local frame = CreateFrame("Frame") local frame = CreateFrame("Frame")
local startTime = GetTime() local startTime = GetTime()
+75 -33
View File
@@ -136,6 +136,12 @@ function Guda_BagFrame_OnHide(self)
addon.Modules.Utils:ClearWorkQueue() addon.Modules.Utils:ClearWorkQueue()
end end
-- Cancel any pending throttled updates
local throttleFrame = getglobal("Guda_BagUpdateThrottle")
if throttleFrame then
throttleFrame:Hide()
end
-- Clean up all buttons when frame is hidden (safe since we're not displaying) -- Clean up all buttons when frame is hidden (safe since we're not displaying)
for _, bagParent in pairs(bagParents) do for _, bagParent in pairs(bagParents) do
if bagParent then if bagParent then
@@ -2503,32 +2509,81 @@ function BagFrame:Initialize()
end end
end) end)
-- Debounce state for BagFrame updates (prevents lag from rapid events) --=====================================================
local bagUpdatePending = false -- Efficient Update Throttling System
local lockUpdatePending = false -- Uses a single reusable frame and true debouncing
-- (resets timer when new events come in)
--=====================================================
local updateThrottle = {
frame = nil,
pending = false,
delay = 0.1, -- Default delay (100ms)
elapsed = 0,
minDelay = 0.05, -- Minimum delay (50ms) for responsive feel
maxDelay = 0.3, -- Maximum delay (300ms) during heavy operations
}
-- Helper to schedule a debounced BagFrame update -- Initialize the throttle frame (created once, reused)
local function ScheduleBagFrameUpdate(delay) local function GetThrottleFrame()
if bagUpdatePending then return end if not updateThrottle.frame then
bagUpdatePending = true updateThrottle.frame = CreateFrame("Frame", "Guda_BagUpdateThrottle", UIParent)
local debounceFrame = CreateFrame("Frame") updateThrottle.frame:Hide()
debounceFrame.elapsed = 0 updateThrottle.frame:SetScript("OnUpdate", function()
debounceFrame:SetScript("OnUpdate", function() updateThrottle.elapsed = updateThrottle.elapsed + arg1
this.elapsed = this.elapsed + arg1 if updateThrottle.elapsed >= updateThrottle.delay then
if this.elapsed >= delay then updateThrottle.frame:Hide()
this:SetScript("OnUpdate", nil) updateThrottle.pending = false
bagUpdatePending = false updateThrottle.elapsed = 0
if not currentViewChar and Guda_BagFrame:IsShown() then -- Only update if frame is shown and viewing current character
BagFrame:Update() if not currentViewChar and Guda_BagFrame and Guda_BagFrame:IsShown() then
BagFrame:Update()
end
end end
end end)
end) end
return updateThrottle.frame
end
-- Schedule a debounced BagFrame update
-- If already pending, resets the timer (true debounce behavior)
local function ScheduleBagFrameUpdate(delay)
delay = delay or updateThrottle.minDelay
-- Clamp delay to reasonable bounds
if delay < updateThrottle.minDelay then
delay = updateThrottle.minDelay
elseif delay > updateThrottle.maxDelay then
delay = updateThrottle.maxDelay
end
-- Use longer delay if sorting is in progress
if addon.Modules.SortEngine and addon.Modules.SortEngine.sortingInProgress then
delay = updateThrottle.maxDelay
end
updateThrottle.delay = delay
updateThrottle.elapsed = 0 -- Reset timer (true debounce)
if not updateThrottle.pending then
updateThrottle.pending = true
GetThrottleFrame():Show()
end
end
-- Cancel any pending update (useful when frame is hidden)
local function CancelPendingUpdate()
if updateThrottle.frame then
updateThrottle.frame:Hide()
end
updateThrottle.pending = false
updateThrottle.elapsed = 0
end end
-- Update on bag changes (debounced to prevent lag on rapid bag updates) -- Update on bag changes (debounced to prevent lag on rapid bag updates)
addon.Modules.Events:OnBagUpdate(function() addon.Modules.Events:OnBagUpdate(function()
if currentViewChar then return end if currentViewChar then return end
if not Guda_BagFrame:IsShown() then return end if not Guda_BagFrame:IsShown() then return end
-- Use standard delay, will auto-extend if sorting is in progress
ScheduleBagFrameUpdate(0.1) ScheduleBagFrameUpdate(0.1)
end, "BagFrame") end, "BagFrame")
@@ -2550,21 +2605,8 @@ function BagFrame:Initialize()
addon.Modules.Events:Register("ITEM_LOCK_CHANGED", function() addon.Modules.Events:Register("ITEM_LOCK_CHANGED", function()
if currentViewChar then return end if currentViewChar then return end
if not Guda_BagFrame:IsShown() then return end if not Guda_BagFrame:IsShown() then return end
-- Use slightly longer debounce for lock changes (they fire rapidly during drags) -- Use slightly longer delay for lock changes (they fire rapidly during drags)
if lockUpdatePending then return end ScheduleBagFrameUpdate(0.15)
lockUpdatePending = true
local debounceFrame = CreateFrame("Frame")
debounceFrame.elapsed = 0
debounceFrame:SetScript("OnUpdate", function()
this.elapsed = this.elapsed + arg1
if this.elapsed >= 0.15 then
this:SetScript("OnUpdate", nil)
lockUpdatePending = false
if Guda_BagFrame:IsShown() then
BagFrame:Update()
end
end
end)
end, "BagFrame") end, "BagFrame")
-- Auto-open bag frame when mail is opened -- Auto-open bag frame when mail is opened
+59 -33
View File
@@ -89,6 +89,12 @@ function Guda_BankFrame_OnHide(self)
-- Clear any pending update -- Clear any pending update
bankPendingUpdate = false bankPendingUpdate = false
-- Cancel any pending throttled updates
local throttleFrame = getglobal("Guda_BankUpdateThrottle")
if throttleFrame then
throttleFrame:Hide()
end
-- Close the actual Blizzard bank too -- Close the actual Blizzard bank too
local blizzardBankFrame = getglobal("BankFrame") local blizzardBankFrame = getglobal("BankFrame")
if blizzardBankFrame and blizzardBankFrame:IsShown() then if blizzardBankFrame and blizzardBankFrame:IsShown() then
@@ -1543,29 +1549,61 @@ function BankFrame:Initialize()
end end
end, "BankFrameUI") end, "BankFrameUI")
-- Update on bag changes while bank is open --=====================================================
-- Debounce state for BankFrame updates (prevents lag from rapid events) -- Efficient Update Throttling System for BankFrame
local bankUpdatePending = false -- Uses a single reusable frame and true debouncing
local bankLockUpdatePending = false --=====================================================
local bankThrottle = {
frame = nil,
pending = false,
delay = 0.1,
elapsed = 0,
minDelay = 0.05,
maxDelay = 0.3,
}
local function GetBankThrottleFrame()
if not bankThrottle.frame then
bankThrottle.frame = CreateFrame("Frame", "Guda_BankUpdateThrottle", UIParent)
bankThrottle.frame:Hide()
bankThrottle.frame:SetScript("OnUpdate", function()
bankThrottle.elapsed = bankThrottle.elapsed + arg1
if bankThrottle.elapsed >= bankThrottle.delay then
bankThrottle.frame:Hide()
bankThrottle.pending = false
bankThrottle.elapsed = 0
if addon.Modules.BankScanner:IsBankOpen() and not currentViewChar then
addon.Modules.BankFrame:Update()
end
end
end)
end
return bankThrottle.frame
end
-- Helper to schedule a debounced BankFrame update
local function ScheduleBankFrameUpdate(delay) local function ScheduleBankFrameUpdate(delay)
if bankUpdatePending then return end
if not addon.Modules.BankScanner:IsBankOpen() then return end if not addon.Modules.BankScanner:IsBankOpen() then return end
if currentViewChar then return end if currentViewChar then return end
bankUpdatePending = true
local debounceFrame = CreateFrame("Frame") delay = delay or bankThrottle.minDelay
debounceFrame.elapsed = 0 if delay < bankThrottle.minDelay then
debounceFrame:SetScript("OnUpdate", function() delay = bankThrottle.minDelay
this.elapsed = this.elapsed + arg1 elseif delay > bankThrottle.maxDelay then
if this.elapsed >= delay then delay = bankThrottle.maxDelay
this:SetScript("OnUpdate", nil) end
bankUpdatePending = false
if addon.Modules.BankScanner:IsBankOpen() and not currentViewChar then -- Use longer delay if sorting is in progress
addon.Modules.BankFrame:Update() if addon.Modules.SortEngine and addon.Modules.SortEngine.sortingInProgress then
end delay = bankThrottle.maxDelay
end end
end)
bankThrottle.delay = delay
bankThrottle.elapsed = 0 -- Reset timer (true debounce)
if not bankThrottle.pending then
bankThrottle.pending = true
GetBankThrottleFrame():Show()
end
end end
addon.Modules.Events:OnBagUpdate(function() addon.Modules.Events:OnBagUpdate(function()
@@ -1578,20 +1616,8 @@ function BankFrame:Initialize()
addon.Modules.Events:Register("ITEM_LOCK_CHANGED", function() addon.Modules.Events:Register("ITEM_LOCK_CHANGED", function()
if not addon.Modules.BankScanner:IsBankOpen() then return end if not addon.Modules.BankScanner:IsBankOpen() then return end
if currentViewChar then return end if currentViewChar then return end
if bankLockUpdatePending then return end -- Use slightly longer delay for lock changes
bankLockUpdatePending = true ScheduleBankFrameUpdate(0.15)
local debounceFrame = CreateFrame("Frame")
debounceFrame.elapsed = 0
debounceFrame:SetScript("OnUpdate", function()
this.elapsed = this.elapsed + arg1
if this.elapsed >= 0.15 then
this:SetScript("OnUpdate", nil)
bankLockUpdatePending = false
if addon.Modules.BankScanner:IsBankOpen() then
addon.Modules.BankFrame:Update()
end
end
end)
end, "BankFrameUI") end, "BankFrameUI")
-- Register bank-specific update events (pfUI style, debounced) -- Register bank-specific update events (pfUI style, debounced)