mirror of
https://github.com/AmberGraceRblx/luau-promise.git
synced 2025-04-24 15:50:01 +00:00
Initial forked version
This commit is contained in:
parent
2c6f433903
commit
558b61fe3d
12 changed files with 259 additions and 92 deletions
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
|
@ -1 +0,0 @@
|
||||||
patreon: erynlynn
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@ node_modules/
|
||||||
.vscode
|
.vscode
|
||||||
build
|
build
|
||||||
roblox.toml
|
roblox.toml
|
||||||
|
sourcemap.json
|
|
@ -1,5 +1,14 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## FORKED VERSION [4.0.0]
|
||||||
|
- Added `any` type annotations to many variables in the internal implementation in order to prevent crashes while using this library
|
||||||
|
- Added `--!nonstrict` compiler directive at the top of the script to expose types
|
||||||
|
- Added library-user-facing typings for `Promise`, `Error`, `Status` and the library itself. This fork uses the `(object :: any) :: PublicType` idiom to simplify the types to the library, allowing for better autocompletion and type annotations in a strict-mode Luau codebase
|
||||||
|
|
||||||
|
No other changes have been made to the library's runtime behavior.
|
||||||
|
|
||||||
|
Please notify me through the issues section if any issues are encountered related to type safety or crashes. Otherwise, please send any issues related to runtime behavior to the [original repository](https://github.com/evaera/roblox-lua-promise).
|
||||||
|
|
||||||
## [4.0.0]
|
## [4.0.0]
|
||||||
### Changed
|
### Changed
|
||||||
- `Promise:finally` no longer observes a rejection from a Promise. Calling `Promise:finally` is mostly transparent now.
|
- `Promise:finally` no longer observes a rejection from a Promise. Calling `Promise:finally` is mostly transparent now.
|
||||||
|
|
1
LICENSE
1
LICENSE
|
@ -1,5 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Amber Grace
|
||||||
Copyright (c) 2019 Eryn L. K.
|
Copyright (c) 2019 Eryn L. K.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>Roblox Lua Promise</h1>
|
<h1>Roblox Luau Promise</h1>
|
||||||
<p>An implementation of <code>Promise</code> similar to Promise/A+.</p>
|
<p>An implementation of <code>Promise</code> similar to Promise/A+.</p>
|
||||||
<a href="https://eryn.io/roblox-lua-promise/"><strong>View docs</strong></a>
|
<a href="https://eryn.io/roblox-lua-promise/"><strong>View docs</strong></a>
|
||||||
</div>
|
</div>
|
||||||
<!--moonwave-hide-before-this-line-->
|
<!--moonwave-hide-before-this-line-->
|
||||||
|
|
||||||
|
|
||||||
## Why you should use Promises
|
## Why you should use Promises
|
||||||
|
|
||||||
The way Roblox models asynchronous operations by default is by yielding (stopping) the thread and then resuming it when the future value is available. This model is not ideal because:
|
The way Roblox models asynchronous operations by default is by yielding (stopping) the thread and then resuming it when the future value is available. This model is not ideal because:
|
||||||
|
@ -20,3 +19,9 @@ This Promise implementation attempts to satisfy these traits:
|
||||||
* An object that represents a unit of asynchronous work
|
* An object that represents a unit of asynchronous work
|
||||||
* Composability
|
* Composability
|
||||||
* Predictable timing
|
* Predictable timing
|
||||||
|
|
||||||
|
## FORKED VERSION
|
||||||
|
|
||||||
|
This is a forked version of [Evaera's Promise library](https://github.com/evaera/roblox-lua-promise) with type annotations added to allow this library to be used in a strict-mode [Luau](https://luau-lang.org) project. Type annotations are imperfect due to limitations with the Luau language, but should at least cover intellisense and basic static analysis.
|
||||||
|
|
||||||
|
Please notify me through the issues section if any issues are encountered related to type safety or crashes. Otherwise, please send any issues related to runtime behavior to the [original repository](https://github.com/evaera/roblox-lua-promise).
|
26
lib/LICENSE.luau
Normal file
26
lib/LICENSE.luau
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
return [[
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Amber Grace
|
||||||
|
Copyright (c) 2019 Eryn L. K.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
]]
|
|
@ -1,13 +1,144 @@
|
||||||
|
--!nonstrict
|
||||||
--[[
|
--[[
|
||||||
An implementation of Promises similar to Promise/A+.
|
An implementation of Promises similar to Promise/A+
|
||||||
|
|
||||||
|
Original library by Eryn L. K.
|
||||||
|
Edit by Amber Grace (@DataBrain) to include custom type annotations & extensions
|
||||||
|
Forked from github repository: evaera/roblox-lua-promise
|
||||||
|
Forked from release V4.0.0 (Mar 2nd 2022).
|
||||||
|
|
||||||
|
I do not intend to maintain
|
||||||
|
this forked version of the library unless a major bug or exploit is
|
||||||
|
found with the original library that needs to be patched here.
|
||||||
|
|
||||||
|
Licensed under MIT License (see nested module for full license)
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
export type Status = "Started" | "Resolved" | "Rejected" | "Cancelled"
|
||||||
|
export type Executor = (
|
||||||
|
resolve: (...any) -> (),
|
||||||
|
reject: (...any) -> (),
|
||||||
|
onCancel: (abortHandler: (() -> ())?) -> boolean
|
||||||
|
) -> ()
|
||||||
|
export type Promise = {
|
||||||
|
timeout: (self: Promise, seconds: number, rejectionValue: any?) -> Promise,
|
||||||
|
getStatus: (self: Promise) -> Status,
|
||||||
|
andThen: (
|
||||||
|
self: Promise,
|
||||||
|
successHandler: (...any) -> ...any,
|
||||||
|
failureHandler: ((...any) -> ...any)?
|
||||||
|
) -> Promise,
|
||||||
|
catch: (
|
||||||
|
self: Promise,
|
||||||
|
failureHandler: (...any) -> ...any
|
||||||
|
) -> Promise,
|
||||||
|
tap: (
|
||||||
|
self: Promise,
|
||||||
|
tapHandler: (...any) -> ...any
|
||||||
|
) -> Promise,
|
||||||
|
andThenCall: <T...>(
|
||||||
|
self: Promise,
|
||||||
|
callback: (T...) -> any,
|
||||||
|
T...
|
||||||
|
) -> Promise,
|
||||||
|
andThenReturn: (
|
||||||
|
self: Promise,
|
||||||
|
...any
|
||||||
|
) -> Promise,
|
||||||
|
cancel: (self: Promise) -> (),
|
||||||
|
finally: (
|
||||||
|
self: Promise,
|
||||||
|
finallyHandler: (status: Status) -> ...any
|
||||||
|
) -> Promise,
|
||||||
|
finallyCall: <T...>(
|
||||||
|
self: Promise,
|
||||||
|
callback: (T...) -> any,
|
||||||
|
T...
|
||||||
|
) -> Promise,
|
||||||
|
finallyReturn: (
|
||||||
|
self: Promise,
|
||||||
|
...any
|
||||||
|
) -> Promise,
|
||||||
|
awaitStatus: (
|
||||||
|
self: Promise
|
||||||
|
) -> (Status, ...any),
|
||||||
|
await: (self: Promise) -> (boolean, ...any),
|
||||||
|
expect: (self: Promise) -> ...any,
|
||||||
|
now: (self: Promise, rejectionValue: any?) -> Promise,
|
||||||
|
}
|
||||||
|
export type ErrorKind = "ExecutionError" | "AlreadyCancelled" | "NotResolvedInTime" | "TimedOut"
|
||||||
|
export type ErrorOptions = {
|
||||||
|
error: string?,
|
||||||
|
trace: string?,
|
||||||
|
context: string?,
|
||||||
|
kind: ErrorKind
|
||||||
|
}
|
||||||
|
export type Error = {
|
||||||
|
kind: ErrorKind,
|
||||||
|
trace: string?,
|
||||||
|
context: string?,
|
||||||
|
parent: Error?,
|
||||||
|
error: string,
|
||||||
|
createdTick: number,
|
||||||
|
createdTrace: string,
|
||||||
|
|
||||||
|
extend: (self: Error, options: ErrorOptions) -> Error,
|
||||||
|
getErrorChain: (self: Error) -> {Error},
|
||||||
|
}
|
||||||
|
type PromiseLib = {
|
||||||
|
new: (executor: Executor) -> Promise,
|
||||||
|
defer: (executor: Executor) -> Promise,
|
||||||
|
resolve: (...any) -> Promise,
|
||||||
|
reject: (...any) -> Promise,
|
||||||
|
try: <T...>(
|
||||||
|
callback: (T...) -> ...any,
|
||||||
|
T...
|
||||||
|
) -> Promise,
|
||||||
|
all: (promises: {Promise}) -> Promise,
|
||||||
|
fold: (
|
||||||
|
list: {any},
|
||||||
|
reducer: (accumulator: any, value: any, index: number) -> any,
|
||||||
|
initialValue: any
|
||||||
|
) -> (),
|
||||||
|
some: (promises: {Promise}, count: number) -> Promise,
|
||||||
|
any: (promises: {Promise}) -> Promise,
|
||||||
|
allSettled: (promises: {Promise}) -> Promise,
|
||||||
|
race: (promises: {Promise}) -> Promise,
|
||||||
|
each: (
|
||||||
|
list: {any},
|
||||||
|
predicate: (value: any, index: number) -> any
|
||||||
|
) -> Promise,
|
||||||
|
is: (object: any) -> boolean,
|
||||||
|
promisify: <T...>(
|
||||||
|
callback: (T...) -> ...any
|
||||||
|
) -> ((T...) -> Promise),
|
||||||
|
delay: (seconds: number) -> Promise,
|
||||||
|
retry: <P...>(
|
||||||
|
callback: (P...) -> Promise,
|
||||||
|
times: number,
|
||||||
|
P...
|
||||||
|
) -> Promise,
|
||||||
|
retryWithDelay: <P...>(
|
||||||
|
callback: (P...) -> Promise,
|
||||||
|
times: number,
|
||||||
|
seconds: number,
|
||||||
|
P...
|
||||||
|
) -> Promise,
|
||||||
|
fromEvent: (
|
||||||
|
event: RBXScriptSignal | {Connect: any},
|
||||||
|
predicate: ((...any) -> boolean)?
|
||||||
|
) -> Promise,
|
||||||
|
onUnhandledRejection: (
|
||||||
|
callback: (Promise, ...any) -> ()
|
||||||
|
) -> (() -> ())
|
||||||
|
}
|
||||||
|
|
||||||
local ERROR_NON_PROMISE_IN_LIST = "Non-promise value passed into %s at index %s"
|
local ERROR_NON_PROMISE_IN_LIST = "Non-promise value passed into %s at index %s"
|
||||||
local ERROR_NON_LIST = "Please pass a list of promises to %s"
|
local ERROR_NON_LIST = "Please pass a list of promises to %s"
|
||||||
local ERROR_NON_FUNCTION = "Please pass a handler function to %s!"
|
local ERROR_NON_FUNCTION = "Please pass a handler function to %s!"
|
||||||
local MODE_KEY_METATABLE = { __mode = "k" }
|
local MODE_KEY_METATABLE: any = { __mode = "k" }
|
||||||
|
|
||||||
local function isCallable(value)
|
local function isCallable(value: any)
|
||||||
if type(value) == "function" then
|
if type(value) == "function" then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -25,7 +156,7 @@ end
|
||||||
--[[
|
--[[
|
||||||
Creates an enum dictionary with some metamethods to prevent common mistakes.
|
Creates an enum dictionary with some metamethods to prevent common mistakes.
|
||||||
]]
|
]]
|
||||||
local function makeEnum(enumName, members)
|
local function makeEnum(enumName: any, members: any)
|
||||||
local enum = {}
|
local enum = {}
|
||||||
|
|
||||||
for _, memberName in ipairs(members) do
|
for _, memberName in ipairs(members) do
|
||||||
|
@ -49,7 +180,7 @@ end
|
||||||
|
|
||||||
@class Error
|
@class Error
|
||||||
]=]
|
]=]
|
||||||
local Error
|
local Error: any
|
||||||
do
|
do
|
||||||
Error = {
|
Error = {
|
||||||
Kind = makeEnum("Promise.Error.Kind", {
|
Kind = makeEnum("Promise.Error.Kind", {
|
||||||
|
@ -61,7 +192,7 @@ do
|
||||||
}
|
}
|
||||||
Error.__index = Error
|
Error.__index = Error
|
||||||
|
|
||||||
function Error.new(options, parent)
|
function Error.new(options: any, parent: any)
|
||||||
options = options or {}
|
options = options or {}
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
error = tostring(options.error) or "[This error has no error text.]",
|
error = tostring(options.error) or "[This error has no error text.]",
|
||||||
|
@ -74,7 +205,7 @@ do
|
||||||
}, Error)
|
}, Error)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Error.is(anything)
|
function Error.is(anything: any)
|
||||||
if type(anything) == "table" then
|
if type(anything) == "table" then
|
||||||
local metatable = getmetatable(anything)
|
local metatable = getmetatable(anything)
|
||||||
|
|
||||||
|
@ -86,13 +217,13 @@ do
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function Error.isKind(anything, kind)
|
function Error.isKind(anything: any, kind: any)
|
||||||
assert(kind ~= nil, "Argument #2 to Promise.Error.isKind must not be nil")
|
assert(kind ~= nil, "Argument #2 to Promise.Error.isKind must not be nil")
|
||||||
|
|
||||||
return Error.is(anything) and anything.kind == kind
|
return Error.is(anything) and anything.kind == kind
|
||||||
end
|
end
|
||||||
|
|
||||||
function Error:extend(options)
|
function Error:extend(options: any)
|
||||||
options = options or {}
|
options = options or {}
|
||||||
|
|
||||||
options.kind = options.kind or self.kind
|
options.kind = options.kind or self.kind
|
||||||
|
@ -134,21 +265,21 @@ end
|
||||||
|
|
||||||
Used to cajole varargs without dropping sparse values.
|
Used to cajole varargs without dropping sparse values.
|
||||||
]]
|
]]
|
||||||
local function pack(...)
|
local function pack(...: any)
|
||||||
return select("#", ...), { ... }
|
return select("#", ...), { ... }
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Returns first value (success), and packs all following values.
|
Returns first value (success), and packs all following values.
|
||||||
]]
|
]]
|
||||||
local function packResult(success, ...)
|
local function packResult(success: any, ...: any)
|
||||||
return success, select("#", ...), { ... }
|
return success, select("#", ...), { ... }
|
||||||
end
|
end
|
||||||
|
|
||||||
local function makeErrorHandler(traceback)
|
local function makeErrorHandler(traceback: any)
|
||||||
assert(traceback ~= nil, "traceback is nil")
|
assert(traceback ~= nil, "traceback is nil")
|
||||||
|
|
||||||
return function(err)
|
return function(err: any)
|
||||||
-- If the error object is already a table, forward it directly.
|
-- If the error object is already a table, forward it directly.
|
||||||
-- Should we extend the error here and add our own trace?
|
-- Should we extend the error here and add our own trace?
|
||||||
|
|
||||||
|
@ -168,7 +299,7 @@ end
|
||||||
--[[
|
--[[
|
||||||
Calls a Promise executor with error handling.
|
Calls a Promise executor with error handling.
|
||||||
]]
|
]]
|
||||||
local function runExecutor(traceback, callback, ...)
|
local function runExecutor(traceback: any, callback: any, ...: any)
|
||||||
return packResult(xpcall(callback, makeErrorHandler(traceback), ...))
|
return packResult(xpcall(callback, makeErrorHandler(traceback), ...))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -176,8 +307,8 @@ end
|
||||||
Creates a function that invokes a callback with correct error handling and
|
Creates a function that invokes a callback with correct error handling and
|
||||||
resolution mechanisms.
|
resolution mechanisms.
|
||||||
]]
|
]]
|
||||||
local function createAdvancer(traceback, callback, resolve, reject)
|
local function createAdvancer(traceback: any, callback: any, resolve: any, reject: any)
|
||||||
return function(...)
|
return function(...: any)
|
||||||
local ok, resultLength, result = runExecutor(traceback, callback, ...)
|
local ok, resultLength, result = runExecutor(traceback, callback, ...)
|
||||||
|
|
||||||
if ok then
|
if ok then
|
||||||
|
@ -188,7 +319,7 @@ local function createAdvancer(traceback, callback, resolve, reject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function isEmpty(t)
|
local function isEmpty(t: any)
|
||||||
return next(t) == nil
|
return next(t) == nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -217,22 +348,23 @@ end
|
||||||
@class Promise
|
@class Promise
|
||||||
@__index prototype
|
@__index prototype
|
||||||
]=]
|
]=]
|
||||||
local Promise = {
|
local Promise: any = {
|
||||||
Error = Error,
|
Error = Error,
|
||||||
Status = makeEnum("Promise.Status", { "Started", "Resolved", "Rejected", "Cancelled" }),
|
Status = makeEnum("Promise.Status", { "Started", "Resolved", "Rejected", "Cancelled" }),
|
||||||
_getTime = os.clock,
|
_getTime = os.clock,
|
||||||
_timeEvent = game:GetService("RunService").Heartbeat,
|
_timeEvent = game:GetService("RunService").Heartbeat,
|
||||||
_unhandledRejectionCallbacks = {},
|
_unhandledRejectionCallbacks = {},
|
||||||
|
TEST = nil :: boolean?,
|
||||||
}
|
}
|
||||||
Promise.prototype = {}
|
Promise.prototype = {}
|
||||||
Promise.__index = Promise.prototype
|
Promise.__index = Promise.prototype
|
||||||
|
|
||||||
function Promise._new(traceback, callback, parent)
|
function Promise._new(traceback: any, callback: any, parent: any)
|
||||||
if parent ~= nil and not Promise.is(parent) then
|
if parent ~= nil and not Promise.is(parent) then
|
||||||
error("Argument #2 to Promise.new must be a promise or nil", 2)
|
error("Argument #2 to Promise.new must be a promise or nil", 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
local self = {
|
local self: any = {
|
||||||
-- The executor thread.
|
-- The executor thread.
|
||||||
_thread = nil,
|
_thread = nil,
|
||||||
|
|
||||||
|
@ -275,15 +407,15 @@ function Promise._new(traceback, callback, parent)
|
||||||
|
|
||||||
setmetatable(self, Promise)
|
setmetatable(self, Promise)
|
||||||
|
|
||||||
local function resolve(...)
|
local function resolve(...: any)
|
||||||
self:_resolve(...)
|
self:_resolve(...)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function reject(...)
|
local function reject(...: any)
|
||||||
self:_reject(...)
|
self:_reject(...)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onCancel(cancellationHook)
|
local function onCancel(cancellationHook: any)
|
||||||
if cancellationHook then
|
if cancellationHook then
|
||||||
if self._status == Promise.Status.Cancelled then
|
if self._status == Promise.Status.Cancelled then
|
||||||
cancellationHook()
|
cancellationHook()
|
||||||
|
@ -346,7 +478,7 @@ end
|
||||||
@param executor (resolve: (...: any) -> (), reject: (...: any) -> (), onCancel: (abortHandler?: () -> ()) -> boolean) -> ()
|
@param executor (resolve: (...: any) -> (), reject: (...: any) -> (), onCancel: (abortHandler?: () -> ()) -> boolean) -> ()
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.new(executor)
|
function Promise.new(executor: any)
|
||||||
return Promise._new(debug.traceback(nil, 2), executor)
|
return Promise._new(debug.traceback(nil, 2), executor)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -372,7 +504,7 @@ end
|
||||||
@param executor (resolve: (...: any) -> (), reject: (...: any) -> (), onCancel: (abortHandler?: () -> ()) -> boolean) -> ()
|
@param executor (resolve: (...: any) -> (), reject: (...: any) -> (), onCancel: (abortHandler?: () -> ()) -> boolean) -> ()
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.defer(executor)
|
function Promise.defer(executor: any)
|
||||||
local traceback = debug.traceback(nil, 2)
|
local traceback = debug.traceback(nil, 2)
|
||||||
local promise
|
local promise
|
||||||
promise = Promise._new(traceback, function(resolve, reject, onCancel)
|
promise = Promise._new(traceback, function(resolve, reject, onCancel)
|
||||||
|
@ -415,7 +547,7 @@ Promise.async = Promise.defer
|
||||||
@param ... any
|
@param ... any
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.resolve(...)
|
function Promise.resolve(...: any)
|
||||||
local length, values = pack(...)
|
local length, values = pack(...)
|
||||||
return Promise._new(debug.traceback(nil, 2), function(resolve)
|
return Promise._new(debug.traceback(nil, 2), function(resolve)
|
||||||
resolve(unpack(values, 1, length))
|
resolve(unpack(values, 1, length))
|
||||||
|
@ -432,7 +564,7 @@ end
|
||||||
@param ... any
|
@param ... any
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.reject(...)
|
function Promise.reject(...: any)
|
||||||
local length, values = pack(...)
|
local length, values = pack(...)
|
||||||
return Promise._new(debug.traceback(nil, 2), function(_, reject)
|
return Promise._new(debug.traceback(nil, 2), function(_, reject)
|
||||||
reject(unpack(values, 1, length))
|
reject(unpack(values, 1, length))
|
||||||
|
@ -443,7 +575,7 @@ end
|
||||||
Runs a non-promise-returning function as a Promise with the
|
Runs a non-promise-returning function as a Promise with the
|
||||||
given arguments.
|
given arguments.
|
||||||
]]
|
]]
|
||||||
function Promise._try(traceback, callback, ...)
|
function Promise._try(traceback: any, callback: any, ...: any)
|
||||||
local valuesLength, values = pack(...)
|
local valuesLength, values = pack(...)
|
||||||
|
|
||||||
return Promise._new(traceback, function(resolve)
|
return Promise._new(traceback, function(resolve)
|
||||||
|
@ -474,7 +606,7 @@ end
|
||||||
@param ... T... -- Additional arguments passed to `callback`
|
@param ... T... -- Additional arguments passed to `callback`
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.try(callback, ...)
|
function Promise.try(callback: any, ...: any)
|
||||||
return Promise._try(debug.traceback(nil, 2), callback, ...)
|
return Promise._try(debug.traceback(nil, 2), callback, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -483,7 +615,7 @@ end
|
||||||
* is resolved when all input promises resolve
|
* is resolved when all input promises resolve
|
||||||
* is rejected if ANY input promises reject
|
* is rejected if ANY input promises reject
|
||||||
]]
|
]]
|
||||||
function Promise._all(traceback, promises, amount)
|
function Promise._all(traceback: any, promises: any, amount: any)
|
||||||
if type(promises) ~= "table" then
|
if type(promises) ~= "table" then
|
||||||
error(string.format(ERROR_NON_LIST, "Promise.all"), 3)
|
error(string.format(ERROR_NON_LIST, "Promise.all"), 3)
|
||||||
end
|
end
|
||||||
|
@ -588,7 +720,7 @@ end
|
||||||
@param promises {Promise<T>}
|
@param promises {Promise<T>}
|
||||||
@return Promise<{T}>
|
@return Promise<{T}>
|
||||||
]=]
|
]=]
|
||||||
function Promise.all(promises)
|
function Promise.all(promises: any)
|
||||||
return Promise._all(debug.traceback(nil, 2), promises)
|
return Promise._all(debug.traceback(nil, 2), promises)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -617,7 +749,7 @@ end
|
||||||
@param reducer (accumulator: U, value: T, index: number) -> U | Promise<U>
|
@param reducer (accumulator: U, value: T, index: number) -> U | Promise<U>
|
||||||
@param initialValue U
|
@param initialValue U
|
||||||
]=]
|
]=]
|
||||||
function Promise.fold(list, reducer, initialValue)
|
function Promise.fold(list: any, reducer: any, initialValue: any)
|
||||||
assert(type(list) == "table", "Bad argument #1 to Promise.fold: must be a table")
|
assert(type(list) == "table", "Bad argument #1 to Promise.fold: must be a table")
|
||||||
assert(isCallable(reducer), "Bad argument #2 to Promise.fold: must be a function")
|
assert(isCallable(reducer), "Bad argument #2 to Promise.fold: must be a function")
|
||||||
|
|
||||||
|
@ -650,7 +782,7 @@ end
|
||||||
@param count number
|
@param count number
|
||||||
@return Promise<{T}>
|
@return Promise<{T}>
|
||||||
]=]
|
]=]
|
||||||
function Promise.some(promises, count)
|
function Promise.some(promises: any, count: any)
|
||||||
assert(type(count) == "number", "Bad argument #2 to Promise.some: must be a number")
|
assert(type(count) == "number", "Bad argument #2 to Promise.some: must be a number")
|
||||||
|
|
||||||
return Promise._all(debug.traceback(nil, 2), promises, count)
|
return Promise._all(debug.traceback(nil, 2), promises, count)
|
||||||
|
@ -674,7 +806,7 @@ end
|
||||||
@param promises {Promise<T>}
|
@param promises {Promise<T>}
|
||||||
@return Promise<T>
|
@return Promise<T>
|
||||||
]=]
|
]=]
|
||||||
function Promise.any(promises)
|
function Promise.any(promises: {any})
|
||||||
return Promise._all(debug.traceback(nil, 2), promises, 1):andThen(function(values)
|
return Promise._all(debug.traceback(nil, 2), promises, 1):andThen(function(values)
|
||||||
return values[1]
|
return values[1]
|
||||||
end)
|
end)
|
||||||
|
@ -696,7 +828,7 @@ end
|
||||||
@param promises {Promise<T>}
|
@param promises {Promise<T>}
|
||||||
@return Promise<{Status}>
|
@return Promise<{Status}>
|
||||||
]=]
|
]=]
|
||||||
function Promise.allSettled(promises)
|
function Promise.allSettled(promises: any)
|
||||||
if type(promises) ~= "table" then
|
if type(promises) ~= "table" then
|
||||||
error(string.format(ERROR_NON_LIST, "Promise.allSettled"), 2)
|
error(string.format(ERROR_NON_LIST, "Promise.allSettled"), 2)
|
||||||
end
|
end
|
||||||
|
@ -774,7 +906,7 @@ end
|
||||||
@param promises {Promise<T>}
|
@param promises {Promise<T>}
|
||||||
@return Promise<T>
|
@return Promise<T>
|
||||||
]=]
|
]=]
|
||||||
function Promise.race(promises)
|
function Promise.race(promises: any)
|
||||||
assert(type(promises) == "table", string.format(ERROR_NON_LIST, "Promise.race"))
|
assert(type(promises) == "table", string.format(ERROR_NON_LIST, "Promise.race"))
|
||||||
|
|
||||||
for i, promise in pairs(promises) do
|
for i, promise in pairs(promises) do
|
||||||
|
@ -869,7 +1001,7 @@ end
|
||||||
@param predicate (value: T, index: number) -> U | Promise<U>
|
@param predicate (value: T, index: number) -> U | Promise<U>
|
||||||
@return Promise<{U}>
|
@return Promise<{U}>
|
||||||
]=]
|
]=]
|
||||||
function Promise.each(list, predicate)
|
function Promise.each(list: any, predicate: any)
|
||||||
assert(type(list) == "table", string.format(ERROR_NON_LIST, "Promise.each"))
|
assert(type(list) == "table", string.format(ERROR_NON_LIST, "Promise.each"))
|
||||||
assert(isCallable(predicate), string.format(ERROR_NON_FUNCTION, "Promise.each"))
|
assert(isCallable(predicate), string.format(ERROR_NON_FUNCTION, "Promise.each"))
|
||||||
|
|
||||||
|
@ -959,6 +1091,7 @@ function Promise.each(list, predicate)
|
||||||
end
|
end
|
||||||
|
|
||||||
resolve(results)
|
resolve(results)
|
||||||
|
return
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -968,7 +1101,7 @@ end
|
||||||
@param object any
|
@param object any
|
||||||
@return boolean -- `true` if the given `object` is a Promise.
|
@return boolean -- `true` if the given `object` is a Promise.
|
||||||
]=]
|
]=]
|
||||||
function Promise.is(object)
|
function Promise.is(object: any)
|
||||||
if type(object) ~= "table" then
|
if type(object) ~= "table" then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
@ -1017,8 +1150,8 @@ end
|
||||||
@param callback (...: any) -> ...any
|
@param callback (...: any) -> ...any
|
||||||
@return (...: any) -> Promise
|
@return (...: any) -> Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.promisify(callback)
|
function Promise.promisify(callback: any)
|
||||||
return function(...)
|
return function(...: any)
|
||||||
return Promise._try(debug.traceback(nil, 2), callback, ...)
|
return Promise._try(debug.traceback(nil, 2), callback, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1048,7 +1181,7 @@ do
|
||||||
local first
|
local first
|
||||||
local connection
|
local connection
|
||||||
|
|
||||||
function Promise.delay(seconds)
|
function Promise.delay(seconds: any)
|
||||||
assert(type(seconds) == "number", "Bad argument #1 to Promise.delay, must be a number.")
|
assert(type(seconds) == "number", "Bad argument #1 to Promise.delay, must be a number.")
|
||||||
-- If seconds is -INF, INF, NaN, or less than 1 / 60, assume seconds is 1 / 60.
|
-- If seconds is -INF, INF, NaN, or less than 1 / 60, assume seconds is 1 / 60.
|
||||||
-- This mirrors the behavior of wait()
|
-- This mirrors the behavior of wait()
|
||||||
|
@ -1056,7 +1189,7 @@ do
|
||||||
seconds = 1 / 60
|
seconds = 1 / 60
|
||||||
end
|
end
|
||||||
|
|
||||||
return Promise._new(debug.traceback(nil, 2), function(resolve, _, onCancel)
|
return Promise._new(debug.traceback(nil, 2), function(resolve: any, _: any, onCancel: any)
|
||||||
local startTime = Promise._getTime()
|
local startTime = Promise._getTime()
|
||||||
local endTime = startTime + seconds
|
local endTime = startTime + seconds
|
||||||
|
|
||||||
|
@ -1177,7 +1310,7 @@ end
|
||||||
@param rejectionValue? any -- The value to reject with if the timeout is reached
|
@param rejectionValue? any -- The value to reject with if the timeout is reached
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:timeout(seconds, rejectionValue)
|
function Promise.prototype:timeout(seconds: any, rejectionValue: any)
|
||||||
local traceback = debug.traceback(nil, 2)
|
local traceback = debug.traceback(nil, 2)
|
||||||
|
|
||||||
return Promise.race({
|
return Promise.race({
|
||||||
|
@ -1210,7 +1343,7 @@ end
|
||||||
|
|
||||||
The given callbacks are invoked depending on that result.
|
The given callbacks are invoked depending on that result.
|
||||||
]]
|
]]
|
||||||
function Promise.prototype:_andThen(traceback, successHandler, failureHandler)
|
function Promise.prototype:_andThen(traceback: any, successHandler: any, failureHandler: any)
|
||||||
self._unhandledRejection = false
|
self._unhandledRejection = false
|
||||||
|
|
||||||
-- If we are already cancelled, we return a cancelled Promise
|
-- If we are already cancelled, we return a cancelled Promise
|
||||||
|
@ -1222,7 +1355,7 @@ function Promise.prototype:_andThen(traceback, successHandler, failureHandler)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create a new promise to follow this part of the chain
|
-- Create a new promise to follow this part of the chain
|
||||||
return Promise._new(traceback, function(resolve, reject, onCancel)
|
return Promise._new(traceback, function(resolve: any, reject: any, onCancel: any)
|
||||||
-- Our default callbacks just pass values onto the next promise.
|
-- Our default callbacks just pass values onto the next promise.
|
||||||
-- This lets success and failure cascade correctly!
|
-- This lets success and failure cascade correctly!
|
||||||
|
|
||||||
|
@ -1280,7 +1413,7 @@ end
|
||||||
@param failureHandler? (...: any) -> ...any
|
@param failureHandler? (...: any) -> ...any
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:andThen(successHandler, failureHandler)
|
function Promise.prototype:andThen(successHandler: any, failureHandler: any)
|
||||||
assert(successHandler == nil or isCallable(successHandler), string.format(ERROR_NON_FUNCTION, "Promise:andThen"))
|
assert(successHandler == nil or isCallable(successHandler), string.format(ERROR_NON_FUNCTION, "Promise:andThen"))
|
||||||
assert(failureHandler == nil or isCallable(failureHandler), string.format(ERROR_NON_FUNCTION, "Promise:andThen"))
|
assert(failureHandler == nil or isCallable(failureHandler), string.format(ERROR_NON_FUNCTION, "Promise:andThen"))
|
||||||
|
|
||||||
|
@ -1307,7 +1440,7 @@ end
|
||||||
@param failureHandler (...: any) -> ...any
|
@param failureHandler (...: any) -> ...any
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:catch(failureHandler)
|
function Promise.prototype:catch(failureHandler: any)
|
||||||
assert(failureHandler == nil or isCallable(failureHandler), string.format(ERROR_NON_FUNCTION, "Promise:catch"))
|
assert(failureHandler == nil or isCallable(failureHandler), string.format(ERROR_NON_FUNCTION, "Promise:catch"))
|
||||||
return self:_andThen(debug.traceback(nil, 2), nil, failureHandler)
|
return self:_andThen(debug.traceback(nil, 2), nil, failureHandler)
|
||||||
end
|
end
|
||||||
|
@ -1328,9 +1461,9 @@ end
|
||||||
@param tapHandler (...: any) -> ...any
|
@param tapHandler (...: any) -> ...any
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:tap(tapHandler)
|
function Promise.prototype:tap(tapHandler: any)
|
||||||
assert(isCallable(tapHandler), string.format(ERROR_NON_FUNCTION, "Promise:tap"))
|
assert(isCallable(tapHandler), string.format(ERROR_NON_FUNCTION, "Promise:tap"))
|
||||||
return self:_andThen(debug.traceback(nil, 2), function(...)
|
return self:_andThen(debug.traceback(nil, 2), function(...: any)
|
||||||
local callbackReturn = tapHandler(...)
|
local callbackReturn = tapHandler(...)
|
||||||
|
|
||||||
if Promise.is(callbackReturn) then
|
if Promise.is(callbackReturn) then
|
||||||
|
@ -1363,7 +1496,7 @@ end
|
||||||
@param ...? any -- Additional arguments which will be passed to `callback`
|
@param ...? any -- Additional arguments which will be passed to `callback`
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:andThenCall(callback, ...)
|
function Promise.prototype:andThenCall(callback: any, ...: any)
|
||||||
assert(isCallable(callback), string.format(ERROR_NON_FUNCTION, "Promise:andThenCall"))
|
assert(isCallable(callback), string.format(ERROR_NON_FUNCTION, "Promise:andThenCall"))
|
||||||
local length, values = pack(...)
|
local length, values = pack(...)
|
||||||
return self:_andThen(debug.traceback(nil, 2), function()
|
return self:_andThen(debug.traceback(nil, 2), function()
|
||||||
|
@ -1393,7 +1526,7 @@ end
|
||||||
@param ... any -- Values to return from the function
|
@param ... any -- Values to return from the function
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:andThenReturn(...)
|
function Promise.prototype:andThenReturn(...: any)
|
||||||
local length, values = pack(...)
|
local length, values = pack(...)
|
||||||
return self:_andThen(debug.traceback(nil, 2), function()
|
return self:_andThen(debug.traceback(nil, 2), function()
|
||||||
return unpack(values, 1, length)
|
return unpack(values, 1, length)
|
||||||
|
@ -1439,7 +1572,7 @@ end
|
||||||
Used to decrease the number of consumers by 1, and if there are no more,
|
Used to decrease the number of consumers by 1, and if there are no more,
|
||||||
cancel this promise.
|
cancel this promise.
|
||||||
]]
|
]]
|
||||||
function Promise.prototype:_consumerCancelled(consumer)
|
function Promise.prototype:_consumerCancelled(consumer: any)
|
||||||
if self._status ~= Promise.Status.Started then
|
if self._status ~= Promise.Status.Started then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -1455,10 +1588,10 @@ end
|
||||||
Used to set a handler for when the promise resolves, rejects, or is
|
Used to set a handler for when the promise resolves, rejects, or is
|
||||||
cancelled.
|
cancelled.
|
||||||
]]
|
]]
|
||||||
function Promise.prototype:_finally(traceback, finallyHandler)
|
function Promise.prototype:_finally(traceback: any, finallyHandler: any)
|
||||||
self._unhandledRejection = false
|
self._unhandledRejection = false
|
||||||
|
|
||||||
local promise = Promise._new(traceback, function(resolve, reject, onCancel)
|
local promise = Promise._new(traceback, function(resolve: any, reject: any, onCancel: any)
|
||||||
local handlerPromise
|
local handlerPromise
|
||||||
|
|
||||||
onCancel(function()
|
onCancel(function()
|
||||||
|
@ -1474,7 +1607,7 @@ function Promise.prototype:_finally(traceback, finallyHandler)
|
||||||
|
|
||||||
local finallyCallback = resolve
|
local finallyCallback = resolve
|
||||||
if finallyHandler then
|
if finallyHandler then
|
||||||
finallyCallback = function(...)
|
finallyCallback = function(...: any)
|
||||||
local callbackReturn = finallyHandler(...)
|
local callbackReturn = finallyHandler(...)
|
||||||
|
|
||||||
if Promise.is(callbackReturn) then
|
if Promise.is(callbackReturn) then
|
||||||
|
@ -1486,7 +1619,7 @@ function Promise.prototype:_finally(traceback, finallyHandler)
|
||||||
resolve(self)
|
resolve(self)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
:catch(function(...)
|
:catch(function(...: any)
|
||||||
reject(...)
|
reject(...)
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
|
@ -1556,7 +1689,7 @@ end
|
||||||
@param finallyHandler (status: Status) -> ...any
|
@param finallyHandler (status: Status) -> ...any
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:finally(finallyHandler)
|
function Promise.prototype:finally(finallyHandler: any)
|
||||||
assert(finallyHandler == nil or isCallable(finallyHandler), string.format(ERROR_NON_FUNCTION, "Promise:finally"))
|
assert(finallyHandler == nil or isCallable(finallyHandler), string.format(ERROR_NON_FUNCTION, "Promise:finally"))
|
||||||
return self:_finally(debug.traceback(nil, 2), finallyHandler)
|
return self:_finally(debug.traceback(nil, 2), finallyHandler)
|
||||||
end
|
end
|
||||||
|
@ -1570,7 +1703,7 @@ end
|
||||||
@param ...? any -- Additional arguments which will be passed to `callback`
|
@param ...? any -- Additional arguments which will be passed to `callback`
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:finallyCall(callback, ...)
|
function Promise.prototype:finallyCall(callback: any, ...: any)
|
||||||
assert(isCallable(callback), string.format(ERROR_NON_FUNCTION, "Promise:finallyCall"))
|
assert(isCallable(callback), string.format(ERROR_NON_FUNCTION, "Promise:finallyCall"))
|
||||||
local length, values = pack(...)
|
local length, values = pack(...)
|
||||||
return self:_finally(debug.traceback(nil, 2), function()
|
return self:_finally(debug.traceback(nil, 2), function()
|
||||||
|
@ -1596,7 +1729,7 @@ end
|
||||||
@param ... any -- Values to return from the function
|
@param ... any -- Values to return from the function
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:finallyReturn(...)
|
function Promise.prototype:finallyReturn(...: any)
|
||||||
local length, values = pack(...)
|
local length, values = pack(...)
|
||||||
return self:_finally(debug.traceback(nil, 2), function()
|
return self:_finally(debug.traceback(nil, 2), function()
|
||||||
return unpack(values, 1, length)
|
return unpack(values, 1, length)
|
||||||
|
@ -1638,7 +1771,7 @@ function Promise.prototype:awaitStatus()
|
||||||
return self._status
|
return self._status
|
||||||
end
|
end
|
||||||
|
|
||||||
local function awaitHelper(status, ...)
|
local function awaitHelper(status: any, ...: any)
|
||||||
return status == Promise.Status.Resolved, ...
|
return status == Promise.Status.Resolved, ...
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1667,7 +1800,7 @@ function Promise.prototype:await()
|
||||||
return awaitHelper(self:awaitStatus())
|
return awaitHelper(self:awaitStatus())
|
||||||
end
|
end
|
||||||
|
|
||||||
local function expectHelper(status, ...)
|
local function expectHelper(status: any, ...: any)
|
||||||
if status ~= Promise.Status.Resolved then
|
if status ~= Promise.Status.Resolved then
|
||||||
error((...) == nil and "Expected Promise rejected with no value." or (...), 3)
|
error((...) == nil and "Expected Promise rejected with no value." or (...), 3)
|
||||||
end
|
end
|
||||||
|
@ -1724,7 +1857,7 @@ function Promise.prototype:_unwrap()
|
||||||
return success, unpack(self._values, 1, self._valuesLength)
|
return success, unpack(self._values, 1, self._valuesLength)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Promise.prototype:_resolve(...)
|
function Promise.prototype:_resolve(...: any)
|
||||||
if self._status ~= Promise.Status.Started then
|
if self._status ~= Promise.Status.Started then
|
||||||
if Promise.is((...)) then
|
if Promise.is((...)) then
|
||||||
(...):_consumerCancelled(self)
|
(...):_consumerCancelled(self)
|
||||||
|
@ -1745,9 +1878,9 @@ function Promise.prototype:_resolve(...)
|
||||||
|
|
||||||
local chainedPromise = ...
|
local chainedPromise = ...
|
||||||
|
|
||||||
local promise = chainedPromise:andThen(function(...)
|
local promise = chainedPromise:andThen(function(...: any)
|
||||||
self:_resolve(...)
|
self:_resolve(...)
|
||||||
end, function(...)
|
end, function(...: any)
|
||||||
local maybeRuntimeError = chainedPromise._values[1]
|
local maybeRuntimeError = chainedPromise._values[1]
|
||||||
|
|
||||||
-- Backwards compatibility < v2
|
-- Backwards compatibility < v2
|
||||||
|
@ -1771,6 +1904,7 @@ function Promise.prototype:_resolve(...)
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_reject(...)
|
self:_reject(...)
|
||||||
|
return
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if promise._status == Promise.Status.Cancelled then
|
if promise._status == Promise.Status.Cancelled then
|
||||||
|
@ -1795,7 +1929,7 @@ function Promise.prototype:_resolve(...)
|
||||||
self:_finalize()
|
self:_finalize()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Promise.prototype:_reject(...)
|
function Promise.prototype:_reject(...: any)
|
||||||
if self._status ~= Promise.Status.Started then
|
if self._status ~= Promise.Status.Started then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -1886,10 +2020,10 @@ end
|
||||||
@param rejectionValue? any -- The value to reject with if the Promise isn't resolved
|
@param rejectionValue? any -- The value to reject with if the Promise isn't resolved
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:now(rejectionValue)
|
function Promise.prototype:now(rejectionValue: any)
|
||||||
local traceback = debug.traceback(nil, 2)
|
local traceback = debug.traceback(nil, 2)
|
||||||
if self._status == Promise.Status.Resolved then
|
if self._status == Promise.Status.Resolved then
|
||||||
return self:_andThen(traceback, function(...)
|
return self:_andThen(traceback, function(...: any)
|
||||||
return ...
|
return ...
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
|
@ -1931,13 +2065,13 @@ end
|
||||||
@param ...? P
|
@param ...? P
|
||||||
@return Promise<T>
|
@return Promise<T>
|
||||||
]=]
|
]=]
|
||||||
function Promise.retry(callback, times, ...)
|
function Promise.retry(callback: any, times: any, ...: any)
|
||||||
assert(isCallable(callback), "Parameter #1 to Promise.retry must be a function")
|
assert(isCallable(callback), "Parameter #1 to Promise.retry must be a function")
|
||||||
assert(type(times) == "number", "Parameter #2 to Promise.retry must be a number")
|
assert(type(times) == "number", "Parameter #2 to Promise.retry must be a number")
|
||||||
|
|
||||||
local args, length = { ... }, select("#", ...)
|
local args, length = { ... }, select("#", ...)
|
||||||
|
|
||||||
return Promise.resolve(callback(...)):catch(function(...)
|
return Promise.resolve(callback(...)):catch(function(...: any)
|
||||||
if times > 0 then
|
if times > 0 then
|
||||||
return Promise.retry(callback, times - 1, unpack(args, 1, length))
|
return Promise.retry(callback, times - 1, unpack(args, 1, length))
|
||||||
else
|
else
|
||||||
|
@ -1959,14 +2093,14 @@ end
|
||||||
@param ...? P
|
@param ...? P
|
||||||
@return Promise<T>
|
@return Promise<T>
|
||||||
]=]
|
]=]
|
||||||
function Promise.retryWithDelay(callback, times, seconds, ...)
|
function Promise.retryWithDelay(callback: any, times: any, seconds: any, ...: any)
|
||||||
assert(isCallable(callback), "Parameter #1 to Promise.retry must be a function")
|
assert(isCallable(callback), "Parameter #1 to Promise.retry must be a function")
|
||||||
assert(type(times) == "number", "Parameter #2 (times) to Promise.retry must be a number")
|
assert(type(times) == "number", "Parameter #2 (times) to Promise.retry must be a number")
|
||||||
assert(type(seconds) == "number", "Parameter #3 (seconds) to Promise.retry must be a number")
|
assert(type(seconds) == "number", "Parameter #3 (seconds) to Promise.retry must be a number")
|
||||||
|
|
||||||
local args, length = { ... }, select("#", ...)
|
local args, length = { ... }, select("#", ...)
|
||||||
|
|
||||||
return Promise.resolve(callback(...)):catch(function(...)
|
return Promise.resolve(callback(...)):catch(function(...: any)
|
||||||
if times > 0 then
|
if times > 0 then
|
||||||
Promise.delay(seconds):await()
|
Promise.delay(seconds):await()
|
||||||
|
|
||||||
|
@ -2001,12 +2135,12 @@ end
|
||||||
@param predicate? (...: P) -> boolean -- A function which determines if the Promise should resolve with the given value, or wait for the next event to check again.
|
@param predicate? (...: P) -> boolean -- A function which determines if the Promise should resolve with the given value, or wait for the next event to check again.
|
||||||
@return Promise<P>
|
@return Promise<P>
|
||||||
]=]
|
]=]
|
||||||
function Promise.fromEvent(event, predicate)
|
function Promise.fromEvent(event: any, predicate: any)
|
||||||
predicate = predicate or function()
|
predicate = predicate or function()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
return Promise._new(debug.traceback(nil, 2), function(resolve, _, onCancel)
|
return Promise._new(debug.traceback(nil, 2), function(resolve: any, _: any, onCancel: any)
|
||||||
local connection
|
local connection
|
||||||
local shouldDisconnect = false
|
local shouldDisconnect = false
|
||||||
|
|
||||||
|
@ -2019,8 +2153,8 @@ function Promise.fromEvent(event, predicate)
|
||||||
-- Connect returns, connection will still be nil. This happens with events that queue up
|
-- Connect returns, connection will still be nil. This happens with events that queue up
|
||||||
-- events when there's nothing connected, such as RemoteEvents
|
-- events when there's nothing connected, such as RemoteEvents
|
||||||
|
|
||||||
connection = event:Connect(function(...)
|
connection = event:Connect(function(...: any)
|
||||||
local callbackValue = predicate(...)
|
local callbackValue = (predicate :: any)(...)
|
||||||
|
|
||||||
if callbackValue == true then
|
if callbackValue == true then
|
||||||
resolve(...)
|
resolve(...)
|
||||||
|
@ -2040,6 +2174,7 @@ function Promise.fromEvent(event, predicate)
|
||||||
end
|
end
|
||||||
|
|
||||||
onCancel(disconnect)
|
onCancel(disconnect)
|
||||||
|
return
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2053,7 +2188,7 @@ end
|
||||||
@param callback (promise: Promise, ...: any) -- A callback that runs when an unhandled rejection happens.
|
@param callback (promise: Promise, ...: any) -- A callback that runs when an unhandled rejection happens.
|
||||||
@return () -> () -- Function that unregisters the `callback` when called
|
@return () -> () -- Function that unregisters the `callback` when called
|
||||||
]=]
|
]=]
|
||||||
function Promise.onUnhandledRejection(callback)
|
function Promise.onUnhandledRejection(callback: any)
|
||||||
table.insert(Promise._unhandledRejectionCallbacks, callback)
|
table.insert(Promise._unhandledRejectionCallbacks, callback)
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
|
@ -2065,4 +2200,4 @@ function Promise.onUnhandledRejection(callback)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return Promise
|
return (Promise :: any) :: PromiseLib
|
|
@ -1,8 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "evaera/roblox-lua-promise"
|
|
||||||
version = "4.0.0"
|
|
||||||
author = "evaera"
|
|
||||||
content_root = "lib"
|
|
||||||
license = "MIT"
|
|
||||||
|
|
||||||
[dependencies]
|
|
|
@ -1 +0,0 @@
|
||||||
std = "roblox+testez"
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "evaera/promise"
|
name = "ambers-careware/promise"
|
||||||
description = "Promise implementation for Roblox"
|
description = "Promise implementation for Roblox Luau"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
registry = "https://github.com/UpliftGames/wally-index"
|
registry = "https://github.com/UpliftGames/wally-index"
|
||||||
|
|
Loading…
Reference in a new issue