mirror of
https://github.com/AmberGraceRblx/luau-promise.git
synced 2025-04-24 15:50:01 +00:00
parent
f32ebd35bb
commit
cef64024e6
3 changed files with 102 additions and 1 deletions
|
@ -10,6 +10,7 @@
|
|||
- Add Promise.try
|
||||
- Add `done`, `doneCall`, `doneReturn`
|
||||
- Add `andThenReturn`, `finallyReturn`
|
||||
- Add `Promise.delay`, `promise:timeout`
|
||||
|
||||
# 2.4.0
|
||||
|
||||
|
|
|
@ -220,6 +220,18 @@ docs:
|
|||
static: true
|
||||
params: "promises: array<Promise<T>>"
|
||||
returns: Promise<T>
|
||||
- name: delay
|
||||
desc: |
|
||||
Returns a Promise that resolves after `seconds` seconds have passed. The Promise resolves with the actual amount of time that was waited.
|
||||
|
||||
This function is **not** a wrapper around `wait`. `Promise.delay` uses a custom scheduler which provides more accurate timing. As an optimization, cancelling this Promise instantly removes the task from the scheduler.
|
||||
|
||||
::: warning
|
||||
Passing `NaN`, infinity, or a number less than 1/60 is equivalent to passing 1/60.
|
||||
:::
|
||||
params: "seconds: number"
|
||||
returns: Promise<number>
|
||||
static: true
|
||||
- name: is
|
||||
desc: Returns whether the given object is a Promise. This only checks if the object is a table and has an `andThen` method.
|
||||
static: true
|
||||
|
@ -473,12 +485,27 @@ docs:
|
|||
desc: Values to return from the function.
|
||||
returns: Promise<...any?>
|
||||
|
||||
- name: timeout
|
||||
params: "seconds: number, rejectionValue: any?"
|
||||
desc: |
|
||||
Returns a new Promise that resolves if the chained Promise resolves within `seconds` seconds, or rejects if execution time exceeds `seconds`. The chained Promise will be cancelled if the timeout is reached.
|
||||
|
||||
Sugar for:
|
||||
|
||||
```lua
|
||||
Promise.race({
|
||||
Promise.delay(seconds):andThen(function()
|
||||
return Promise.reject(rejectionValue == nil and "Timed out" or rejectionValue)
|
||||
end),
|
||||
promise
|
||||
})
|
||||
```
|
||||
|
||||
- name: cancel
|
||||
desc: |
|
||||
Cancels this promise, preventing the promise from resolving or rejecting. Does not do anything if the promise is already settled.
|
||||
|
||||
Cancellations will propagate upwards through chained promises.
|
||||
Cancellations will propagate upwards and downwards through chained promises.
|
||||
|
||||
Promises will only be cancelled if all of their consumers are also cancelled. This is to say that if you call `andThen` twice on the same promise, and you cancel only one of the child promises, it will not cancel the parent promise until the other child promise is also cancelled.
|
||||
|
||||
|
|
73
lib/init.lua
73
lib/init.lua
|
@ -392,6 +392,79 @@ function Promise.promisify(callback)
|
|||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Creates a Promise that resolves after given number of seconds.
|
||||
]]
|
||||
do
|
||||
local connection
|
||||
local queue = {}
|
||||
|
||||
local function enqueue(callback, seconds)
|
||||
table.insert(queue, {
|
||||
callback = callback,
|
||||
startTime = tick(),
|
||||
endTime = tick() + math.max(seconds, 1/60)
|
||||
})
|
||||
|
||||
table.sort(queue, function(a, b)
|
||||
return a.endTime < b.endTime
|
||||
end)
|
||||
|
||||
if not connection then
|
||||
connection = RunService.Heartbeat:Connect(function()
|
||||
while #queue > 0 and queue[1].endTime <= tick() do
|
||||
local item = table.remove(queue, 1)
|
||||
|
||||
item.callback(tick() - item.startTime)
|
||||
end
|
||||
|
||||
if #queue == 0 then
|
||||
connection:Disconnect()
|
||||
connection = nil
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
local function dequeue(callback)
|
||||
for i, item in ipairs(queue) do
|
||||
if item.callback == callback then
|
||||
table.remove(queue, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Promise.delay(seconds)
|
||||
assert(type(seconds) == "number", "Bad argument #1 to Promise.delay, must be a number.")
|
||||
-- If seconds is -INF, INF, or NaN, assume seconds is 0.
|
||||
-- This mirrors the behavior of wait()
|
||||
if seconds < 0 or seconds == math.huge or seconds ~= seconds then
|
||||
seconds = 0
|
||||
end
|
||||
|
||||
return Promise.new(function(resolve, _, onCancel)
|
||||
enqueue(resolve, seconds)
|
||||
|
||||
onCancel(function()
|
||||
dequeue(resolve)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Rejects the promise after `seconds` seconds.
|
||||
]]
|
||||
function Promise.prototype:timeout(seconds, timeoutValue)
|
||||
return Promise.race({
|
||||
Promise.delay(seconds):andThen(function()
|
||||
return Promise.reject(timeoutValue == nil and "Timed out" or timeoutValue)
|
||||
end),
|
||||
self
|
||||
})
|
||||
end
|
||||
|
||||
function Promise.prototype:getStatus()
|
||||
return self._status
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue