How to wait for data to exist (profileservice)

I am trying to use ProfileService to get and store data. I am also using Knit. I am getting the data before it has time to be loaded in (Getting is printing before data has loaded is printed)

function DataService.Client:ReturnData(player)
	return self.Server:Get(player)
end

function DataService:Get(player)
	local Profile = self.Profiles[player]
	print("Getting")
	if Profile then
		return Profile.Data
	end
end

function DataService:Load(player)
	local ProfileStore = ProfileService.GetProfileStore(
		"PlayerData",
		Template
	)
	
	local Profile = ProfileStore:LoadProfileAsync("Player_" .. player.UserId)
	
	if Profile ~= nil then
		Profile:AddUserId(player.UserId) -- GDPR compliance
		Profile:Reconcile() -- Fill in missing variables from ProfileTemplate (optional)
		
		-- The profile could've been loaded on another Roblox server
		Profile:ListenToRelease(function()
			self.Profiles[player] = nil
			
			player:Kick()
		end)
		
		if player:IsDescendantOf(Players) then -- Profile has been successfully loaded
			self.Profiles[player] = Profile
		else -- Player left before the profile loaded
			Profile:Release()
		end
	else -- Profile couldn't be loaded
		player:Kick() 
	end
	
	print("✅ | Data has loaded!")
end

Ideally, I don’t want to do a loop, so unsure if knit or profileserivce have an actual yield for this

function DataService:Get(player)
	local Profile = self.Profiles[player]

    while not Profile do
        Profile = self.Profiles[player]
        task.wait()
    end

	if Profile then
		return Profile.Data
	end
end

Just do this:

if Profile then
    print("Getting")
	return Profile.Data
end

Or for a custom yield:

local time = tick()
repeat
    local Profile = self.Profiles[player]
until Profile or (tick() - time > 5)

Probably off-topic but you should see this:

I don’t want a loop based thing though, as players can leave, data can fail to load etc and then itll yield forever

Try creating a custom bindable event, for when it’s successful which is in this line of code.

		if player:IsDescendantOf(Players) then -- Profile has been successfully loaded
			self.Profiles[player] = Profile
self.PlayerLoaded[player] = true
self.PlayerLoadedEvents.[player].ProfileLoadedEvent:Fire()

Then for :Get

function DataService:Get(player)
	local Profile = self.Profiles[player]
if not Profile then
self.PlayerLoadedEvents.[player]:Wait()
end

Even then it will still have a chance to fail and yield forever.

So you will still need to listen if it fails and send a :Fire again with a message saying “I failed” with the status.

Perhaps a Promise might be better because you can do :await() or :cancel it once the player leaves. Also it seems to be designed for this sort of scenario as it is asynchronous with the possibility of the data failing like the http example but I’m not an expert on it.

3 Likes

Kinda old now. But with the loop you can just make sure the player isn’t nil and repeat task.wait() until not Player or Profile ~= nil