Promise/A+ compliant implementation written for Garry's Mod written in Yuescript
Promises represent the result of an operation which will complete in the future. They can be passed around, chained onto, and can help to flatten out deeply nested callback code, and simplify error handling to some degree.
This library has a lot of similarities JS Promises, so checkout them.
Also there are many, and much better, introductions to promise patterns.
This library is dependent on gm_error
Copy promise.lua
and error.lua
(from gm_error)
into your project and then include it
local Promise = include("promise.lua")
If you want to include promises in clientside, do not forget to AddCSLuaFile
them
AddCSLuaFile("error.lua")
AddCSLuaFile("promise.lua")
local Promise = include("promise.lua")
local p = Promise()
p:Resolve(123)
p:Then(function(value)
print("Promise was fulfilled with", value)
end, function(reason)
print("Promise was rejected with", value)
end)
-- Will print 'Promise was fulfilled with 123'
local p = Promise(function(resolve, reject)
resolve("hello world")
end)
print(p) -- Will print 'Promise 0x12345678 { <state>: "fulfilled", <value>: hello world }'
local p = Promise()
timer.Simple(1, function()
p:Resolve()
end)
p:Then(function()
print("Promise fulfilled!")
end)
-- 'Promise fulfilled' will be printed after 1 second
local Promise = include("promise.lua")
local Error = include("error.lua").Error
local p = Promise()
p:Reject( Error("Whoops!") )
p:Catch(function(reason)
print(reason)
-- Will print 'xxx/yyy/zzz.lua:123: Error: Whoops!'
end)
local Promise = include("promise.lua")
local Error = include("error.lua").Error
local function AsyncFetch(url)
local p = Promise()
http.Fetch(url,
-- onSuccess
function(body, length, headers, code)
p:Resolve({
body = body,
length = length,
headers = headers,
code = code
})
end,
-- onFailure
function(message)
p:Reject(Error(message))
end
)
return p
end
local function AsyncJSONFetch(url)
return AsyncFetch(url):Then(function(data)
return util.JSONToTable(data.body)
end)
end
AsyncJSONFetch("https://example.com"):Then(function(data)
-- `data` will be a table that is parsed from json from example.com
PrintTable(data)
end):Catch(function(err)
print("Failed to fetch example.com:", err)
end)
Creates a new promise that can be resolved or rejected
local p = Promise()
p:Then(callback):Catch(callback):Finally(callback)
Creates a new promise that will be resolved or rejected by executor
Executor receives two functions, resolve
and reject
.
If executor throws and error, then the promise will be rejected.
local p = Promise(function(resolve, reject)
resolve("Hello World")
end)
p:Then(function(value)
print(value == "Hello World") -- true
end)
Queues onFulfilled
, onRejected
and onFinally
callbacks,
and promise
will call them after promise will be resolved.
Returns a new promise
Alternative names: promise:next(...)
, promise:andThen(...)
, promise:then(...)
Same as calling promise:Then(nil, onRejected)
Alternative name: promise:catch(...)
Same as calling promise:Then(nil, nil, onFinally)
Alternative name: promise:finally(...)
Resolves promise
with passed value
.
If promise
already resolved or rejected, does nothing.
Alternative name: promise:resolve(...)
Rejects promise
with passed reason
.
If promise
already resolved or rejected, does nothing.
Alternative name: promise:resolve(...)
Returns a new promise that is resolved with passed value
.
Alternative name: Promise.resolve(...)
Returns a new promise that is rejected with passed reason
.
Alternative name: Promise.reject(...)
Returns a new promise that will be resolved with fulfilled values from promises
.
If all promises are rejected, then returned promise will be rejected.
promises
must be a list of promises.
Alternative name: Promise.all(...)
Returns a new promise that will be resolved with values like { status = "fulfilled", value = ... }
or { status = "rejected" , reason = ... }
.
promises
must be a list of promises.
Alternative name: Promise.allSettled(...)
Returns a new promise that will be resolved with first fulfilled promise. If all promises are rejected, then returned promise will be rejected.
Alternative name: Promise.any(...)
Returns a new promise that will be fulfilled/rejected with first resolved promise.
Alternative name: Promise.race(...)
Returns a new promise that will be resolved with value
after time
(in seconds)
Alternative name: Promise.delay(...)
Same as HTTP but will return a new Promise that will be fulfilled or rejected with response from HTTP.
Fulfill value is { code = ..., body = "...", headers = {...} }
Reject value is HTTPError
with a reason of error.
Alternative name: Promise.http(...)
Wraps around given function. Returned function will call func
in coroutine thread, will allow to await promises and return a new promise that will be fulfilled with func
return value, or rejected with error from func
.
Alternative name: Promise.async(...)
local async = Promise.Async
local await = Promise.Await
local fn = async(function()
await( Promise.delay(1) ) -- Waits for one second
return "hello world"
end)
local p = fn()
-- p is a promise that will be resolved with "hello world" after 1 second
Asynchronously waits for promise to resolve. Returns a value if promise was fulfilled, or throws a reason.
Alternative name: Promise:await()
local async = Promise.async
local fn = async(function()
local value = Promise.Delay(1, "hello world"):Await()
print(value == "hello world") -- true
end)
fn()
Same as promise:Await()
, but returns two values instead.
Returns true
and value if promise was fulfilled. Returns false
and reason if promise was rejected.
Alternative name: Promise:saveAwait()
local async = Promise.async
local fn = async(function()
local ok, value = Promise.Delay(1, "hello world"):SafeAwait()
print(ok) -- true
print(value) -- hello world
end)
fn()
Just an extended class from Error
that is used to reject a promise in Promise.HTTP(...)
- 1.2
then
is reserved keyword in Lua.Then
,next
orandThen
must be used instead. - 1.3 Lua have only type
nil
, there is noundefined
- 2.2.5 Lua method calls do not have a
this
equivalent. Theself
syntactic sugar forself
is determined by method arguments. - 2.3.1
TypeError
error object is used from gm_error, since Lua does not have own error objects. - 2.3.3.3 Lua method calls do not have a
this
equivalent.Then
will be called with the first argument of x instead.
This README is inspired by promise.lua. Thanks to him for writing good README :)
Related projects: