Janitor
Janitor is a light-weight, flexible object for cleaning up connections, instances, or anything. This implementation covers all use cases, as it doesn't force you to rely on naive typechecking to guess how an instance should be cleaned up. Instead, the developer may specify any behavior for any object.
Properties
CurrentlyCleaning
This item is read only and cannot be modified. Read OnlyJanitor.CurrentlyCleaning:
boolean
Whether or not the Janitor is currently cleaning up.
SuppressInstanceReDestroy
Janitor.SuppressInstanceReDestroy:
boolean
Whether or not you want to suppress the re-destroying of instances. Default is false, which is the original behavior.
Functions
new
Instantiates a new Janitor object.
Is
Janitor.
Is
(
Object:
any
--
The object you are checking.
) →
boolean
--
true
if Object
is a Janitor.
Determines if the passed object is a Janitor. This checks the metatable directly.
instanceof
Janitor.
instanceof
(
Object:
any
--
The object you are checking.
) →
boolean
--
true
if Object
is a Janitor.
An alias for Janitor.Is. This is intended for roblox-ts support.
Add
Janitor:
Add
(
Object:
T
,
--
The object you want to clean up.
MethodName?:
boolean
|
string
,
--
The name of the method that will be used to clean up. If not passed, it will first check if the object's type exists in TypeDefaults, and if that doesn't exist, it assumes Destroy
.
Index?:
any
--
The index that can be used to clean up the object manually.
) →
T
--
The object that was passed as the first argument.
Adds an Object
to Janitor for later cleanup, where MethodName
is the key of the method within Object
which should be called at cleanup time.
If the MethodName
is true
the Object
itself will be called if it's a function or have task.cancel
called on it if it is a thread. If passed
an index it will occupy a namespace which can be Remove()
d or overwritten. Returns the Object
.
info
Objects not given an explicit MethodName
will be passed into the typeof
function for a very naive typecheck.
RBXConnections will be assigned to "Disconnect", functions and threads will be assigned to true
, and everything else will default to "Destroy".
Not recommended, but hey, you do you.
Luau:
local Workspace = game:GetService("Workspace")
local TweenService = game:GetService("TweenService")
local Obliterator = Janitor.new()
local Part = Workspace.Part
-- Queue the Part to be Destroyed at Cleanup time
Obliterator:Add(Part, "Destroy")
-- Queue function to be called with `true` MethodName
Obliterator:Add(print, true)
-- Close a thread.
Obliterator:Add(task.defer(function()
while true do
print("Running!")
task.wait(0.5)
end
end), true)
-- This implementation allows you to specify behavior for any object
Obliterator:Add(TweenService:Create(Part, TweenInfo.new(1), {Size = Vector3.new(1, 1, 1)}), "Cancel")
-- By passing an Index, the Object will occupy a namespace
-- If "CurrentTween" already exists, it will call :Remove("CurrentTween") before writing
Obliterator:Add(TweenService:Create(Part, TweenInfo.new(1), {Size = Vector3.new(1, 1, 1)}), "Destroy", "CurrentTween")
TypeScript:
import { Workspace, TweenService } from "@rbxts/services";
import { Janitor } from "@rbxts/janitor";
const Obliterator = new Janitor<{ CurrentTween: Tween }>();
const Part = Workspace.FindFirstChild("Part") as Part;
// Queue the Part to be Destroyed at Cleanup time
Obliterator.Add(Part, "Destroy");
// Queue function to be called with `true` MethodName
Obliterator.Add(print, true);
// Close a thread.
Obliterator.Add(task.defer(() => {
while (true) {
print("Running!");
task.wait(0.5);
}
}), true);
// This implementation allows you to specify behavior for any object
Obliterator.Add(TweenService.Create(Part, new TweenInfo(1), {Size: new Vector3(1, 1, 1)}), "Cancel");
// By passing an Index, the Object will occupy a namespace
// If "CurrentTween" already exists, it will call :Remove("CurrentTween") before writing
Obliterator.Add(TweenService.Create(Part, new TweenInfo(1), {Size: new Vector3(1, 1, 1)}), "Destroy", "CurrentTween");
AddObject
Janitor:
AddObject
(
Constructor:
{
new:
(
A...
)
→
T
}
,
--
The constructor for the object you want to add to the Janitor.
MethodName?:
boolean
|
string
,
--
The name of the method that will be used to clean up. If not passed, it will first check if the object's type exists in TypeDefaults, and if that doesn't exist, it assumes Destroy
.
Index?:
any
,
--
The index that can be used to clean up the object manually.
...:
A...
--
The arguments that will be passed to the constructor.
) →
T
--
The object that was passed as the first argument.
Constructs an object for you and adds it to the Janitor. It's really just shorthand for Janitor:Add(Object.new(), MethodName, Index)
.
Luau:
local Obliterator = Janitor.new()
local SubObliterator = Obliterator:AddObject(Janitor, "Destroy")
-- SubObliterator is another Janitor!
TypeScript:
import { Janitor } from "@rbxts/janitor";
const Obliterator = new Janitor();
const SubObliterator = Obliterator.AddObject(Janitor, "Destroy");
AddPromise
Janitor:
AddPromise
(
PromiseObject:
Promise
--
The promise you want to add to the Janitor.
) →
Promise
Adds a Promise to the Janitor. If the Janitor is cleaned up and the Promise is not completed, the Promise will be cancelled.
Luau:
local Obliterator = Janitor.new()
Obliterator:AddPromise(Promise.delay(3)):andThenCall(print, "Finished!"):catch(warn)
task.wait(1)
Obliterator:Cleanup()
TypeScript:
import { Janitor } from "@rbxts/janitor";
const Obliterator = new Janitor();
Obliterator.AddPromise(Promise.delay(3)).andThenCall(print, "Finished!").catch(warn);
task.wait(1);
Obliterator.Cleanup();
Remove
Cleans up whatever Object
was set to this namespace by the 3rd parameter of Janitor.Add.
Luau:
local Obliterator = Janitor.new()
Obliterator:Add(workspace.Baseplate, "Destroy", "Baseplate")
Obliterator:Remove("Baseplate")
TypeScript:
import { Workspace } from "@rbxts/services";
import { Janitor } from "@rbxts/janitor";
const Obliterator = new Janitor<{ Baseplate: Part }>();
Obliterator.Add(Workspace.FindFirstChild("Baseplate") as Part, "Destroy", "Baseplate");
Obliterator.Remove("Baseplate");
RemoveNoClean
Removes an object from the Janitor without running a cleanup.
Luau
local Obliterator = Janitor.new()
Obliterator:Add(function()
print("Removed!")
end, true, "Function")
Obliterator:RemoveNoClean("Function") -- Does not print.
TypeScript:
import { Janitor } from "@rbxts/janitor";
const Obliterator = new Janitor<{ Function: () => void }>();
Obliterator.Add(() => print("Removed!"), true, "Function");
Obliterator.RemoveNoClean("Function"); // Does not print.
RemoveList
Cleans up multiple objects at once.
Luau:
local Obliterator = Janitor.new()
Obliterator:Add(function()
print("Removed One")
end, true, "One")
Obliterator:Add(function()
print("Removed Two")
end, true, "Two")
Obliterator:Add(function()
print("Removed Three")
end, true, "Three")
Obliterator:RemoveList("One", "Two", "Three") -- Prints "Removed One", "Removed Two", and "Removed Three"
TypeScript:
import { Janitor } from "@rbxts/janitor";
type NoOp = () => void
const Obliterator = new Janitor<{ One: NoOp, Two: NoOp, Three: NoOp }>();
Obliterator.Add(() => print("Removed One"), true, "One");
Obliterator.Add(() => print("Removed Two"), true, "Two");
Obliterator.Add(() => print("Removed Three"), true, "Three");
Obliterator.RemoveList("One", "Two", "Three"); // Prints "Removed One", "Removed Two", and "Removed Three"
RemoveListNoClean
Cleans up multiple objects at once without running their cleanup.
Luau:
local Obliterator = Janitor.new()
Obliterator:Add(function()
print("Removed One")
end, true, "One")
Obliterator:Add(function()
print("Removed Two")
end, true, "Two")
Obliterator:Add(function()
print("Removed Three")
end, true, "Three")
Obliterator:RemoveListNoClean("One", "Two", "Three") -- Nothing is printed.
TypeScript:
import { Janitor } from "@rbxts/janitor";
type NoOp = () => void
const Obliterator = new Janitor<{ One: NoOp, Two: NoOp, Three: NoOp }>();
Obliterator.Add(() => print("Removed One"), true, "One");
Obliterator.Add(() => print("Removed Two"), true, "Two");
Obliterator.Add(() => print("Removed Three"), true, "Three");
Obliterator.RemoveListNoClean("One", "Two", "Three"); // Nothing is printed.
Get
Janitor:
Get
(
Index:
any
--
The index that the object is stored under.
) →
any?
--
This will return the object if it is found, but it won't return anything if it doesn't exist.
Gets whatever object is stored with the given index, if it exists. This was added since Maid allows getting the task using __index
.
Luau:
local Obliterator = Janitor.new()
Obliterator:Add(workspace.Baseplate, "Destroy", "Baseplate")
print(Obliterator:Get("Baseplate")) -- Returns Baseplate.
TypeScript:
import { Workspace } from "@rbxts/services";
import { Janitor } from "@rbxts/janitor";
const Obliterator = new Janitor<{ Baseplate: Part }>();
Obliterator.Add(Workspace.FindFirstChild("Baseplate") as Part, "Destroy", "Baseplate");
print(Obliterator.Get("Baseplate")); // Returns Baseplate.
GetAll
Janitor:
GetAll
(
) →
{
[
any
]
:
any
}
Returns a frozen copy of the Janitor's indices.
Luau:
local Obliterator = Janitor.new()
Obliterator:Add(workspace.Baseplate, "Destroy", "Baseplate")
print(Obliterator:GetAll().Baseplate) -- Prints Baseplate.
TypeScript:
import { Workspace } from "@rbxts/services";
import { Janitor } from "@rbxts/janitor";
const Obliterator = new Janitor<{ Baseplate: Part }>();
Obliterator.Add(Workspace.FindFirstChild("Baseplate") as Part, "Destroy", "Baseplate");
print(Obliterator.GetAll().Baseplate); // Prints Baseplate.
Cleanup
Janitor:
Cleanup
(
) →
(
)
Calls each Object's MethodName
(or calls the Object if MethodName == true
) and removes them from the Janitor. Also clears the namespace.
This function is also called when you call a Janitor Object (so it can be used as a destructor callback).
Luau:
Obliterator:Cleanup() -- Valid.
Obliterator() -- Also valid.
TypeScript:
Obliterator.Cleanup()
// TypeScript version doesn't support the __call method of cleaning.
Destroy
Janitor:
Destroy
(
) →
(
)
Calls Janitor.Cleanup and renders the Janitor unusable.
warning
Running this will make any further attempts to call a method of Janitor error.
LinkToInstance
Janitor:
LinkToInstance
(
AllowMultiple?:
boolean
--
Whether or not to allow multiple links on the same Janitor.
) →
RBXScriptConnection
--
A RBXScriptConnection that can be disconnected to prevent the cleanup of LinkToInstance.
"Links" this Janitor to an Instance, such that the Janitor will Cleanup
when the Instance is Destroyed()
and garbage collected.
A Janitor may only be linked to one instance at a time, unless AllowMultiple
is true. When called with a truthy AllowMultiple
parameter,
the Janitor will "link" the Instance without overwriting any previous links, and will also not be overwritable.
When called with a falsy AllowMultiple
parameter, the Janitor will overwrite the previous link which was also called with a falsy AllowMultiple
parameter, if applicable.
Luau:
local Obliterator = Janitor.new()
Obliterator:Add(function()
print("Cleaning up!")
end, true)
do
local Folder = Instance.new("Folder")
Obliterator:LinkToInstance(Folder)
Folder:Destroy()
end
TypeScript:
import { Janitor } from "@rbxts/janitor";
const Obliterator = new Janitor();
Obliterator.Add(() => print("Cleaning up!"), true);
{
const Folder = new Instance("Folder");
Obliterator.LinkToInstance(Folder, false);
Folder.Destroy();
}
LinkToInstances
Janitor:
LinkToInstances
(
) →
Janitor
--
A new Janitor that can be used to manually disconnect all LinkToInstances.
Links several instances to a new Janitor, which is then returned.