Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How do you disconnect events? Stacking them is causing major lag

So for an inventory I'm creating I need it to update the hot bar you know, to do that I'm using a changed event. The problemo is that if you keep using it it'll start to lag because the events keep stacking up. I need to know how to disconnect events.

(Not the entire script, just parts I think you'll need for context)

function update()
	print("Prime update")
	if script.Parent.Image == "" then
		script.Parent.Amount.Visible = false
	else
		if player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil and  player.Inventory[script.Parent.Item.Value].Value == 0 then
			script.Parent.Amount.Visible = false
			script.Parent.Image = ""
			script.Parent.Item.Value = ""
		elseif player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil then
			script.Parent.Amount.Visible = true
			script.Parent.Amount.Text = "x"..player.Inventory[script.Parent.Item.Value].Value
			if a~=nil then
				a = nil
			end			
			local a = player.Inventory[script.Parent.Item.Value].Changed:connect(update)
		end
	end
end

[Completed fixed version]

local player = script.Parent.Parent.Parent.Parent.Parent.Parent.Parent
local a = nil
function onClicked()
	if script.Parent.Image~="" then	
		if game.Workspace:WaitForChild(player.Name):FindFirstChild(script.Parent.Item.Value)~=nil then
			game.Workspace:WaitForChild(player.Name).Humanoid:UnequipTools()
		else
		 	game.Workspace:WaitForChild(player.Name).Humanoid:UnequipTools()
			game.Workspace:WaitForChild(player.Name).Humanoid:EquipTool(game.ReplicatedStorage.assets.Items[script.Parent.Item.Value]:Clone())
		end
		local kids = player.Backpack:GetChildren()
		for i=1,#kids do
			if kids[i].ClassName == "Tool" then
				kids[i]:Destroy()
			end
		end
	elseif script.Parent.Image == "" then
		game.Workspace:WaitForChild(player.Name).Humanoid:UnequipTools()
	end
end

function update()
	print("Prime update")
	if script.Parent.Image == "" then
		script.Parent.Amount.Visible = false
		if a~=nil then
			a:disconnect()
		end		
	else
		if player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil and  player.Inventory[script.Parent.Item.Value].Value == 0 then
			script.Parent.Amount.Visible = false
			script.Parent.Image = ""
			script.Parent.Item.Value = ""
		elseif player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil then
			script.Parent.Amount.Visible = true
			script.Parent.Amount.Text = "x"..player.Inventory[script.Parent.Item.Value].Value		
		end
	end
end

script.Parent.Item.Changed:connect(function()
	if a~=nil then
		a:disconnect()
	end
	if script.Parent.Item.Value~="" then
		a = player.Inventory[script.Parent.Item.Value].Changed:connect(update)
	end
end)

userInput = game:GetService("UserInputService")
userInput.InputBegan:connect(function(input)
	if input.UserInputType == Enum.UserInputType.Keyboard and input.UserInputState == Enum.UserInputState.Begin and input.KeyCode == Enum.KeyCode.One then

		onClicked()
	
	end
end)

game.Players.LocalPlayer.CharacterAdded:connect(function(character)
	update()
end)

script.Parent.MouseButton1Click:connect(onClicked)
script.Parent.Changed:connect(update)

wait(10)
update()
if player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil then
	script.Parent.Amount.Text = "x"..player.Inventory[script.Parent.Item.Value].Value
else
	script.Parent.Amount.Text = ""
end

2 answers

✓ Accepted answer

You never need more than one event for the same job


If you're ever in a situation where you're connecting multiple events to the same object within a loop, another event, or multiple times without disconnecting them, you need to fix that immediately. When setting up an event listener, ROBLOX does not overwrite the previous one (as you've probably figured out).

Instead, you need to disconnect the previous event manually if you're going to be throwing it away, or connecting more of the same events to the object. You can do this by using the disconnect method on what your connect method returns. Here's an example:

-- "PartTouched" now represents what "connect()" returns, which is the event signal for this individual event.
local PartTouched = Part.Touched:connect(function()
	print("Part touched")
end)

-- Once you have a reference to that signal, you can then disconnect it by calling the "disconnect()" method on it whenever you want.
PartTouched:disconnect()

Only firing once

Now, sometimes you only want an event to fire once at a time. You could use a debounce strategy, which is probably better 90% of the time. But for that specific situation where the event must be disconnected right after it fires, this is how it'd be done:

  • A reference to the event must be defined outside it's callback function

    • You could avoid doing this by using a global variable (i.e, a non-local variable), but that's not good practice. What you should do, is define a local variable with no value to tell the script you're going to assign something to it later.
  • Disconnect the event as soon as it fires

    • In case something might fire your event twice immediately and your code yields at some point before disconnecting the event, you should always disconnect it before doing anything else.

Understanding this, here's an example of how it'd be done:

-- Making the local variable "PartTouched" with a default value of nil. Now we can reference this variable outside our callback function we pass to the event
local PartTouched

PartTouched = Part.Touched:connect(function()
	-- We can disconnect it, since we set it to the signal the event returns
	PartTouched:disconnect()

	-- The rest of your code
	print("Hello")
end)

While disconnecting events is important if you're going to be using creating more than one for the same object, it can also be unnecessary in avoidable situations. Most of the time, you can just have one event constantly listening for something without needing to mess with disconnect or debounce. In the case of your code, this can be implemented by simply taking your event connection out of your update function, and have it somewhere where it's only going to be created that one time.

Hope that helped, if you have any questions or if anything was unclear, just let me know and I'll get back to you as soon as possible.

1 comment

0

The reason why I'm doing it this way is because the item there changes and I don't want it to go through all 100+ items in my game just to get this one thing. I tried putting a:disconnect() on line 14 but it didn't work. Am I using it incorrectly?

Just put something like this in:

myFunction:disconnect()

Substitute 'myFunction' for the name of the function you want to disconnect.

2 comments

0

You don't disconnect the function, you disconnect the signal the connect method returns.

0

I put 'a:disconnect()' on line 14 and it didn't help

This discussion is preserved as it was. New answers, comments, and votes are closed.