https://github.com/LPGhatguy/roblox-lua-promise
(NO LONGER MAINTAINED) An implementation of promises akin to JavaScript's Promises/A+
https://github.com/LPGhatguy/roblox-lua-promise
Last synced: about 1 year ago
JSON representation
(NO LONGER MAINTAINED) An implementation of promises akin to JavaScript's Promises/A+
- Host: GitHub
- URL: https://github.com/LPGhatguy/roblox-lua-promise
- Owner: LPGhatguy
- License: cc0-1.0
- Archived: true
- Created: 2018-01-25T22:50:16.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2019-09-10T04:25:47.000Z (over 6 years ago)
- Last Synced: 2025-03-11T11:51:25.447Z (about 1 year ago)
- Language: Lua
- Homepage:
- Size: 29.3 KB
- Stars: 23
- Watchers: 4
- Forks: 4
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-roblox - ROBLOX Lua Promise
README
# Roblox Lua Promise
An implementation of `Promise` similar to Promise/A+.
### This project is no longer maintained. I recommend [evaera's Promise implementation](https://github.com/evaera/roblox-lua-promise), which is a fork that implements cancellation and is actively maintained!
## Motivation
I've found that being able to yield anywhere causes lots of bugs. In [Rodux](https://github.com/Roblox/Rodux), I explicitly made it impossible to yield in a change handler because of the sheer number of bugs that occured when callbacks randomly yielded.
As such, I think that Roblox needs an object-based async primitive. It's not important to me whether these are Promises, Observables, Task objects, or Futures.
The important traits are:
* An object that represents a unit of asynchronous work
* Composability
* Predictable timing
This Promise implementation attempts to satisfy those traits.
## API
### Static Functions
* `Promise.new((resolve, reject) -> nil) -> Promise`
* Construct a new Promise that will be resolved or rejected with the given callbacks.
* `Promise.resolve(value) -> Promise`
* Creates an immediately resolved Promise with the given value.
* `Promise.reject(value) -> Promise`
* Creates an immediately rejected Promise with the given value.
* `Promise.is(object) -> bool`
* Returns whether the given object is a Promise.
* `Promise.all(array) -> array`
* Accepts an array of promises and returns a new promise that:
* is resolved after all input promises resolve.
* is rejected if ANY input promises reject.
* Note: Only the first return value from each promise will be present in the resulting array.
### Instance Methods
* `Promise:andThen(successHandler, [failureHandler]) -> Promise`
* Chains onto an existing Promise and returns a new Promise.
* Equivalent to the Promise/A+ `then` method.
* `Promise:catch(failureHandler) -> Promise`
* Shorthand for `Promise:andThen(nil, failureHandler)`.
* `Promise:await() -> ok, value`
* Yields the current thread until the given Promise completes. Returns `ok` as a bool, followed by the value that the promise returned.
## Example
This Promise implementation finished synchronously. In order to wrap an existing async API, you should use `spawn` or `delay` in order to prevent your calling thread from accidentally yielding.
```lua
local HttpService = game:GetService("HttpService")
-- A light wrapper around HttpService
-- Ideally, you do this once per project per async method that you use.
local function httpGet(url)
return Promise.new(function(resolve, reject)
-- Spawn to prevent yielding, since GetAsync yields.
spawn(function()
local ok, result = pcall(HttpService.GetAsync, HttpService, url)
if ok then
resolve(result)
else
reject(result)
end
end)
end)
end
-- Usage
httpGet("https://google.com")
:andThen(function(body)
print("Here's the Google homepage:", body)
end)
:catch(function(err)
warn("We failed to get the Google homepage!", err)
end)
```
## Future Additions
* `Promise.wrapAsync`
* Intended to wrap an existing Roblox API that yields, exposing a new one that returns a Promise.
## License
This project is available under the CC0 license. See [LICENSE](LICENSE) for details.