Concur
Concurrency class for helping run tasks concurrently. In other words, Concur allows developers to watch coroutines/threads. Completion status, returned values, and errors can all be tracked.
For instance, Concur could be used to concurrently save all player data at the same time when the game closes down:
game:BindToClose(function()
	local all = {}
	for _,player in Players:GetPlayers() do
		local save = Concur.spawn(function()
			DoSomethingToSaveData(player)
		end)
		table.insert(all, save)
	end
	local allConcur = Concur.all(all)
	allConcur:Await()
end)
Types
Errors
interface Errors {Stopped: "Stopped"Timeout: "Timeout"}Properties
Errors
This item is read only and cannot be modified. Read OnlyConcur.Errors:  ErrorsFunctions
spawn
Spawns the function using task.spawn.
local c = Concur.spawn(function()
	task.wait(5)
	return "Hello!"
end)
c:OnCompleted(function(err, msg)
	if err then
		error(err)
	end
	print(msg) --> Hello!
end))
defer
Same as Concur.spawn, but uses task.defer internally.
delay
Same as Concur.spawn, but uses task.delay internally.
value
Resolves to the given value right away.
local val = Concur.value(10)
val:OnCompleted(function(v)
	print(v) --> 10
end)
event
  Completes the Concur instance once the event is fired and the predicate
  function returns true (if no predicate is given, then completes once
  the event first fires).
The Concur instance will return the values given by the event.
-- Wait for next player to touch an object:
local touch = Concur.event(part.Touched, function(toucher)
	return Players:GetPlayerFromCharacter(toucher.Parent) ~= nil
end)
touch:OnCompleted(function(err, toucher)
	print(toucher)
end)
all
Completes once all Concur instances have been completed. All values will be available in a packed table in the same order they were passed.
local c1 = Concur.spawn(function()
	return 10
end)
local c2 = Concur.delay(0.5, function()
	return 15
end)
local c3 = Concur.value(20)
local c4 = Concur.spawn(function()
	error("failed")
end)
Concur.all({c1, c2, c3}):OnCompleted(function(err, values)
	print(values) --> {{nil, 10}, {nil, 15}, {nil, 20}, {"failed", nil}}
end)
first
Completes once the first Concur instance is completed without an error. All other Concur instances are then stopped.
local c1 = Concur.delay(1, function()
	return 10
end)
local c2 = Concur.delay(0.5, function()
	return 5
end)
Concur.first({c1, c2}):OnCompleted(function(err, num)
	print(num) --> 5
end)
Stop
Concur:Stop() → ()
  Stops the Concur instance. The underlying thread will be cancelled using
  task.cancel. Any bound OnCompleted functions or threads waiting with
  Await will be completed with the error Concur.Errors.Stopped.
local c = Concur.spawn(function()
	for i = 1,10 do
		print(i)
		task.wait(1)
	end
end)
task.wait(2.5)
c:Stop() -- At this point, will have only printed 1 and 2
IsCompleted
Concur:IsCompleted() → booleanCheck if the Concur instance is finished.
Await
This is a yielding function. When called, it will pause the Lua thread that called the function until a result is ready to be returned, without interrupting other scripts. YieldsConcur:Await(timeout: number?) → (Error,...any?)Yields the calling thread until the Concur instance is completed:
local c = Concur.delay(5, function()
	return "Hi"
end)
local err, msg = c:Await()
print(msg) --> Hi
  The Await method can be called after the Concur instance
  has been completed too, in which case the completed values
  will be returned immediately without yielding the thread:
local c = Concur.spawn(function()
	return 10
end)
task.wait(5)
-- Called after 'c' has been completed, but still captures the value:
local err, num = c:Await()
print(num) --> 10
  It is always good practice to make sure that the err value is handled
  by checking if it is not nil:
local c = Concur.spawn(function()
	error("failed")
end)
local err, value = c:Await()
if err ~= nil then
	print(err) --> failed
	-- Handle error `err`
else
	-- Handle `value`
end
  This will stop awaiting if the Concur instance was stopped
  too, in which case the err will be equal to
  Concur.Errors.Stopped:
local c = Concur.delay(10, function() end)
c:Stop()
local err = c:Await()
if err == Concur.Errors.Stopped then
	print("Was stopped")
end
  An optional timeout can be given, which will return the
  Concur.Errors.Timeout error if timed out. Timing out
  does not stop the Concur instance, so other callers
  to Await or OnCompleted can still grab the resulting
  values.
local c = Concur.delay(10, function() end)
local err = c:Await(1)
if err == Concur.Errors.Timeout then
	-- Handle timeout
end
OnCompleted
Concur:OnCompleted(fn: (Error,...any?) → (),timeout: number?) → () → ()Calls the given function once the Concur instance is completed:
local c = Concur.delay(5, function()
	return "Hi"
end)
c:OnCompleted(function(err, msg)
	print(msg) --> Hi
end)
A function is returned that can be used to unbind the function to no longer fire when the Concur instance is completed:
local c = Concur.delay(5, function() end)
local unbind = c:OnCompleted(function()
	print("Completed")
end)
unbind()
-- Never prints "Completed"
  The OnCompleted method can be called after the Concur instance
  has been completed too, in which case the given function will be
  called immediately with the completed values:
local c = Concur.spawn(function()
	return 10
end)
task.wait(5)
-- Called after 'c' has been completed, but still captures the value:
c:OnCompleted(function(err, num)
	print(num) --> 10
end)
  It is always good practice to make sure that the err value is handled
  by checking if it is not nil:
local c = Concur.spawn(function()
	error("failed")
end)
c:OnCompleted(function(err, value)
	if err ~= nil then
		print(err) --> failed
		-- Handle error `err`
		return
	end
	-- Handle `value`
end)
  This will call the function if the Concur instance was stopped
  too, in which case the err will be equal to
  Concur.Errors.Stopped:
local c = Concur.delay(10, function() end)
c:OnCompleted(function(err)
	if err == Concur.Errors.Stopped then
		print("Was stopped")
	end
end)
c:Stop()
  An optional timeout can also be supplied, which will call the
  function with the Concur.Errors.Timeout error:
local c = Concur.delay(10, function() end)
c:OnCompleted(function(err)
	if err == Concur.Errors.Timeout then
		-- Handle timeout
	end
end, 1)