This is what I've come up with.
Lua Code:
local AsyncPairs; do
-- Local pointers make lookups faster
local CallErrorHandler=CallErrorHandler;
local debugprofilestop=debugprofilestop;
local next=next;
local table_remove=table.remove;
local unpack=unpack;
local xpcall=xpcall;
local TableStack={};
local TimerFrame=CreateFrame("Frame");
local function TimerFrame_OnUpdate(self,elpased)
local tbldat=TableStack[1];-- Pull from bottom of stack
if tbldat then
local tbl,key,limit,oniterate,onfinish=unpack(tbldat,1,5);-- Extract vars; range is specified since there can be embedded nils
local start=debugprofilestop()-elapsed*1000;-- Offset with frame render time
repeat-- Used instead of While to guarantee at least one iteration
local val; key,val=next(tbl,key);-- Get next key/val pair
if key~=nil then-- We have a key/val pair
local ok=xpcall(oniterate,CallErrorHandler,key,val);-- Dispatch OnIterate callback
if not ok then table_remove(TableStack,1); break; end-- OnError: Remove table from stack and exit
else-- No more key/val pairs
table_remove(TableStack,1);-- Remove from stack
if onfinish then xpcall(onfinish,CallErrorHandler); end-- Dispatch OnFinish callback
break;-- Exit loop
end
until debugprofilestop()-start>=limit-- Checked at end of iteration; compare elapsed time to limit
tbldat[2]=key;-- Store new key for next frame; if table was removed from stack, this is just garbage anyway
else self:SetScript("OnUpdate",nil); end-- Disable if we have nothing on the stack
end
function AsyncPairs(tbl,limit,oniterate,onfinish)
table.insert(TableStack,{tbl,nil,limit,oniterate,onfinish});-- Push to stack
TimerFrame:SetScript("OnUpdate",TimerFrame_OnUpdate);-- Activate timer function
end
end
Usage:
AsyncPairs(
Table,
Limit,
OnIterate[,
OnFinish])
Limit is in milliseconds.
OnIterate and
OnFinish are callbacks with the later being optional.