GithubHelp home page GithubHelp logo

howmanysmall / janitor Goto Github PK

View Code? Open in Web Editor NEW
97.0 7.0 18.0 1.93 MB

Janitor library.

Home Page: https://howmanysmall.github.io/Janitor/

License: MIT License

Lua 100.00%
maid janitor roblox luau gc cleanup

janitor's Introduction

Janitor

Janitor library. This branch is for the thread safe version of Janitor that does not use a global state.

Original was made by Validark, however he doesn't really maintain that version anymore. It does have all the original documentation for it though.

Now on roblox-ts!

Projects that use Janitor

If your project uses Janitor, leave a PR on the readme!

Why use Janitor?

  • Janitor makes dealing with garbage collection much less annoying and stressful because it manages them all in a nice interface.
  • Janitor:Add returns whatever was added, which Maid doesn't.
  • Janitor:Add also accepts a custom method, if you want to call :Stop on a Tween. You can see this being used in the JanitorPromise library.
  • Janitor:Add also accepts a custom reference to store under, which keeps the api more consistent. (Maid.A = X and Maid:GiveTask(Y) vs Janitor:Add(X, nil, "A") and Janitor:Add(Y))
  • Janitor also allows linking to an Instance, so when the Instance is destroyed, the Janitor cleans up everything along with it.

Some less important benefits:

  • Runs a little better than Maid does.

Performance

Janitor runs incredibly well. It is quite a bit faster than Maid and around as fast as Dumpster. You can run the benchmark for yourself using boatbomber's benchmark plugin and the bench found here.

Benchmark results

Benchmarks ran on an R9 3900X with 32GB of DDR4-3600 RAM.

janitor's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

janitor's Issues

Add `LinkToInstanceRemoval`

This is just a shorthand way of checking if an Instance was removed / parented to nil. This is only being considered because of this information on this tweet, as it's worrying.

function Janitor.__index:LinkToInstanceRemoval(Object, AllowMultiple)
	local function AncestryChanged(_, Parent)
		if not Parent then
			self:Cleanup()
		end
	end

	if AllowMultiple then
		return self:Add(Object.AncestryChanged:Connect(AncestryChanged), "Disconnect")
	else
		return self:Add(Object.AncestryChanged:Connect(AncestryChanged), "Disconnect", LinkToInstanceIndex)
	end
end

Do not use os.clock

os.clock should only be used for it's intended purpose, which is benchmarking as stated on the wiki. It does not reflect upon actual time but rather CPU time - time() is a better alternative for this.

Cleanup cleanups that make cleanups

During cleanup, the Maid class will keep iterating throughout all tasks until they are all cleaned up. This takes care of cases where a cleanup function will create another cleanup. Imo, there really shouldn't be cleanup functions making cleanup functions in the first place, but it's a feature to consider.

Cancelling a thread from within itself will error.

A minimum example can be seen here:

const janitor = new Janitor();
janitor.Add(task.delay(1, () => janitor.Destroy()));

@rbxts.janitor.src:612: invalid argument #1 to 'cancel' (thread expected, got nil).

This is because we task.defer the thread cancel, but by this point Object is no longer valid. This could be fixed by checking if Object is still valid before we try to cancel it.

if not Cancelled then
    task.defer(function()
        task.cancel(Object)
    end)
end

My use case here is a thread that I want to end after X amount of time, but I also wish to have the ability to cancel the thread early by name of an event from another place. I want to be able to clear up both the task.delay and the event connection to end this thread early, but the thread will not necessarily be cleaned up early.

Refactor Janitor's source code

Currently the source of Janitor is a bit of a mess as I'm pretty much just hacking together things. A full refactor might be in order to make it so the codebase is less hacky.

No deterministic ordering of cleanup functions causes race conditions

Consider a janitor as such

local janitor = Janitor.new()
local camera = workspace.CurrentCamera

-- doing some work which requires custom camera control ...

-- if camera type changes (e.g. corescript), then change to scriptable it
janitor:Add(camera:GetPropertyChangedSignal("CameraType"):Connect(function()
    camera.CameraType = Enum.CameraType.Scriptable
end)

-- reset camera type to custom on cleanup
janitor:Add(function()
    camera.CameraType = Enum.CameraType.Custom
end)

-- stuff  ...

-- no longer need custom camera control
janitor:Cleanup()

depending on the ordering of the cleanup, camera type may end up as Scriptable if the reset function was called before the connection was disconnected. The ideal scenario is that it should always end up as Custom.

This cropped up when converting existing usage of Quenty's maid to janitor, which had deterministic ordering of cleanup.

Cleanup should ideally be applied using a queue or stack based approach. Or alternatively with a priority mechanism.

Issue with closing threads

When I add threads to the janitor, and put the method as true as the documentation says it ends up erroring

energyJanitor.Add(task.defer(() => {
        while (true) {
            task.wait(3)

            if ((zoneEnergy?.GetChildren().size() ?? 0) <= 30) {
                SpawnEnergy(world)
            }
        }
    }), true);

ReplicatedStorage.rbxts_include.node_modules.@rbxts.knit.Knit.Util.Janitor:76: attempt to index thread with boolean

Convert LinkToInstance to use AncestryChanged

sleitnick brought up a good point about the while true do and wait usage in LinkToInstance being an odd choice. AncestryChanged should work the same as well as removing any extra dependencies.

Add support for Quenty's Promise library.

Adding support for Quenty's Promise library would be beneficial if people use both in their codebase.

Here's some example code on how this could be done, although it isn't exactly peak code quality. It could also be separated into two functions, but that would mean extra work on the user's end.

function Janitor.__index:AddPromise(PromiseObject)
	if Promise_is(PromiseObject) then
		if PromiseObject:getStatus() == Promise.Status.Started then
			local Id = newproxy(false)
			local NewPromise = self:Add(Promise.resolve(PromiseObject), "cancel", Id)
			NewPromise:finallyCall(self.Remove, self, Id)
			return NewPromise
		end
	else
		local Promise_isPromise = PromiseObject.isPromise
		if Promise_isPromise and type(Promise_isPromise) == "function" and Promise_isPromise(PromiseObject) then
			if PromiseObject:IsPending() then
				local Id = newproxy(false)
				local NewPromise = self:Add(PromiseObject.resolved(PromiseObject), "Destroy", Id)
				NewPromise:Finally(function()
					self:Remove(Id)
				end)

				return NewPromise
			end
		end
	end

	return PromiseObject
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.