How do I wait until a function returns data?

Basically I have code that is suppose to get data from a function, but the data doesnt get returned in an instant, so how do I make it wait til the data gets returned?

Trigger Code

AnimateButton.Click:Connect(function()
	displayMsg(true,'SELECT RIGS TO ANIMATE')
	
	local s = getSelected()
	
	print(s)
	
	if s then
		print(s)
	end
end)

Function

local function getSelected()

	
	uis.InputBegan:Connect(function(input)
		if input.KeyCode == Enum.KeyCode.R then
			print('Gettin selections')
			local s = {}
			for _, item in pairs(selectionService:Get()) do
				if item:FindFirstChildOfClass('Humanoid') then
					s[item.Name] = item
				end
			end
			return s
		end
	end)
end
AnimateButton.Click:Connect(function()
	displayMsg(true,'SELECT RIGS TO ANIMATE')
	local s = nil
	s = getSelected()
    
	repeat 
		task.wait()
    until (s ~= nil)
	
	print(s)
end)
1 Like

This didnt work, I made it print “Yes” after it S should be equal to something but it never is or something

	displayMsg(true,'SELECT RIGS TO ANIMATE')
	
	local s = getSelected()
	
	local t = 30
	
	repeat 
		task.wait() t -= 0.03 
	until (s ~= nil) or t <= 0
	
	print('yes') -- never gets printed
	displayMsg(false)
	
	if s then
		print(s)
	else
		warn('DID NOT SELECT ANY RIGS')
	end

That is because you’re not inserting any data into s. You should use table.insert instead.

Therefore:

local function getSelected()
    uis.InputBegan:Connect(function(input)
        
		if input.KeyCode == Enum.KeyCode.R then
		    local Return = {}
			print('Gettin selections')
			
			for _, item in pairs(selectionService:Get()) do

				if item:FindFirstChildOfClass('Humanoid') then
					table.insert(Return, item)

				end
			end
			
			return Return
			
		end
	end)
end
1 Like

Yes they are?

This is inserting an item into the s table

It should insert the value then. I don’t know whether table[i.Name] = i is correct, however.

It does, can confirm.

@FroDev1002 could you print s BEFORE the repeat until loop and see what it prints?

this is true, I remember that table.insert would work instead of the other method

Tried doing this, it still returns nil even though there are things in S. I print it before I return it.

Just btw, I’m fairly certain this will cause a memory leak because the UIS.InputBegan connection is not disconnected and is reconnected every click of the UI button.

Dont worry I will disconnect it later, I was trying to figure this out first

RBXScriptSignal has a /Wait method that yields the thread and then resumes with the arguments once the event is fired. So instead of /Connect, you could do:

local function getSelected()
	local input, wasProcessed = UserInputService.InputBegan:Wait()
	
	if not wasProcessed and input.KeyCode == Enum.KeyCode.R then
		...
	end
end

You could also put it in a loop to retry yielding in the case the user input something that wasn’t R or was processed.

Ok but what about actually returning the value? Unless this is to do with that. Im dum obv

You could possibly do this:

local runService = game:GetService("RunService")
local function getSelected()
    local items = nil
	local connection = uis.InputBegan:Connect(function(input) -- store the connection so it can be disconnected later
		if input.KeyCode == Enum.KeyCode.R then
			print('Gettin selections')
			local s = {}
			for _, item in pairs(selectionService:Get()) do
				if item:FindFirstChildOfClass('Humanoid') then
					s[item.Name] = item
				end
			end
			items = s -- set the items variable to 's'
		end
	end)

    while not items do -- yield the thread until the 'items' variable isn't nil
       runService.Heartbeat:Wait() -- wait every frame
    end
    connection:Disconnect() -- disconnect the input connection
    return items -- return the data
end
1 Like

this could possibly work, i haven’t tested it though:

local function getSelected()
	local running = coroutine.running()
	uis.InputBegan:Connect(function(input)
		if input.KeyCode == Enum.KeyCode.R then
			print('Gettin selections')
			local s = {}
			for _, item in pairs(selectionService:Get()) do
				if item:FindFirstChildOfClass('Humanoid') then
					s[item.Name] = item
				end
			end
			coroutine.resume(running)
			return s
		end
	end)
	coroutine.yield()
end

no weird while loops, though I’m concerned about how you are not disconnecting the inputbegan event

You should look into using an open source module such as promise which provides a ton of methods for pausing the thread until data has been returned.
https://eryn.io/roblox-lua-promise/

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.