Skip to main content

LoaderScheduler

Budgets the synchronous work the loader does while walking the package tree.

Bootstrapping recurses over every folder, module script and value in the tree in one go, which on a large game can exhaust Roblox's script execution timeout. Callers thread a scheduler through that recursion and call LoaderScheduler.YieldIfNeededAsync as they walk, which spreads the work over frames instead of blowing the whole budget at once.

Functions​

new​

LoaderScheduler.new(
label: string,--

Names the walk being budgeted, for debug output

budgetBeforeYield: number?--

Seconds of work allowed before yielding

) → LoaderScheduler

Constructs a new scheduler with a fresh budget.

isLoaderScheduler​

LoaderScheduler.isLoaderScheduler(loaderScheduler: any?) → boolean

Returns true if the argument is a loader scheduler

RestartBudget​

LoaderScheduler.RestartBudget(
startTime: number?--

Defaults to now

) → ()

Starts the budget over without yielding. Use this when the caller has already yielded for its own reasons.

Pass a start time from LoaderScheduler.GetBudgetStartTime to continue a window another scheduler already opened, so work handed between schedulers inside one frame keeps counting against that frame instead of each walk being handed a full budget.

GetBudgetStartTime​

LoaderScheduler.GetBudgetStartTime(self: LoaderScheduler) → number?

When the current budget window started, or nil if none is open.

ClearBudget​

LoaderScheduler.ClearBudget(self: LoaderScheduler) → ()

Clears the budget so the next LoaderScheduler.YieldIfNeededAsync starts a fresh window. Use this when the walk is done, otherwise the next caller measures against however long ago we last yielded.

GetTotalComputeTime​

LoaderScheduler.GetTotalComputeTime(self: LoaderScheduler) → number

Total time spent computing, excluding time spent yielded. Compare against wall clock time to see what the yielding is costing.

YieldIfNeededAsync​

LoaderScheduler.YieldIfNeededAsync(self: LoaderScheduler) → boolean--

true if we yielded

Yields if this frame's budget is spent, otherwise returns immediately.

Callers that yield here have to revalidate whatever they captured before the call, since the tree can change while we're yielded.

Show raw api
{
    "functions": [
        {
            "name": "new",
            "desc": "Constructs a new scheduler with a fresh budget.",
            "params": [
                {
                    "name": "label",
                    "desc": "Names the walk being budgeted, for debug output",
                    "lua_type": "string"
                },
                {
                    "name": "budgetBeforeYield",
                    "desc": "Seconds of work allowed before yielding",
                    "lua_type": "number?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "LoaderScheduler"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 39,
                "path": "src/loader/src/Timing/LoaderScheduler.lua"
            }
        },
        {
            "name": "isLoaderScheduler",
            "desc": "Returns true if the argument is a loader scheduler",
            "params": [
                {
                    "name": "loaderScheduler",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 60,
                "path": "src/loader/src/Timing/LoaderScheduler.lua"
            }
        },
        {
            "name": "RestartBudget",
            "desc": "Starts the budget over without yielding. Use this when the caller has\nalready yielded for its own reasons.\n\nPass a start time from [LoaderScheduler.GetBudgetStartTime] to continue a\nwindow another scheduler already opened, so work handed between schedulers\ninside one frame keeps counting against that frame instead of each walk\nbeing handed a full budget.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "LoaderScheduler"
                },
                {
                    "name": "startTime",
                    "desc": "Defaults to now",
                    "lua_type": "number?"
                }
            ],
            "returns": [],
            "function_type": "static",
            "source": {
                "line": 75,
                "path": "src/loader/src/Timing/LoaderScheduler.lua"
            }
        },
        {
            "name": "GetBudgetStartTime",
            "desc": "When the current budget window started, or nil if none is open.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "LoaderScheduler"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "number?"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 86,
                "path": "src/loader/src/Timing/LoaderScheduler.lua"
            }
        },
        {
            "name": "ClearBudget",
            "desc": "Clears the budget so the next [LoaderScheduler.YieldIfNeededAsync] starts a\nfresh window. Use this when the walk is done, otherwise the next caller\nmeasures against however long ago we last yielded.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "LoaderScheduler"
                }
            ],
            "returns": [],
            "function_type": "static",
            "source": {
                "line": 95,
                "path": "src/loader/src/Timing/LoaderScheduler.lua"
            }
        },
        {
            "name": "GetTotalComputeTime",
            "desc": "Total time spent computing, excluding time spent yielded. Compare against\nwall clock time to see what the yielding is costing.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "LoaderScheduler"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "number"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 105,
                "path": "src/loader/src/Timing/LoaderScheduler.lua"
            }
        },
        {
            "name": "YieldIfNeededAsync",
            "desc": "Yields if this frame's budget is spent, otherwise returns immediately.\n\nCallers that yield here have to revalidate whatever they captured before\nthe call, since the tree can change while we're yielded.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "LoaderScheduler"
                }
            ],
            "returns": [
                {
                    "desc": "true if we yielded",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 121,
                "path": "src/loader/src/Timing/LoaderScheduler.lua"
            }
        }
    ],
    "properties": [],
    "types": [],
    "name": "LoaderScheduler",
    "desc": "Budgets the synchronous work the loader does while walking the package tree.\n\nBootstrapping recurses over every folder, module script and value in the\ntree in one go, which on a large game can exhaust Roblox's script execution\ntimeout. Callers thread a scheduler through that recursion and call\n[LoaderScheduler.YieldIfNeededAsync] as they walk, which spreads the work over\nframes instead of blowing the whole budget at once.",
    "source": {
        "line": 13,
        "path": "src/loader/src/Timing/LoaderScheduler.lua"
    }
}