Giter Site home page Giter Site logo

roblox-lua-promise's Introduction

Roblox Lua Promise

An implementation of Promise similar to Promise/A+.

This project is no longer maintained. I recommend evaera's Promise implementation, 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, 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.

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 for details.

roblox-lua-promise's People

Contributors

benbrimeyer avatar evaera avatar lpghatguy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

roblox-lua-promise's Issues

Use coroutines instead of xpcall

If this promise implementation wrapped each callback in a coroutine instead of using xpcall, then wrapping APIs that yield wouldn't require spawn. It would also help guard against cases where users yield intentionally or otherwise.

One thing to note is that we probably lose the ability to track errors after a yield has occurred. The current version bans yielding entirely, a previous version allowed it by virtue of using pcall, and this version would catch errors, but only if they occur before the first yield.

Tag stable releases

Stable releases should be tagged so we can track incremental changes and big release changes

Switch to three-arg variant of unpack in most places

This library has a lot of places that involve packing up varargs into a table and using unpack to pull them back out. If those varargs have nil values in the middle, they'll get swallowed up!

Anywhere where we use unpack(t), we should instead use unpack(t, start, finish) and manually keep the length of the input varargs via select("#", ...). Perhaps polyfilling table.pack is the way to go.

Failures from Promise.all cannot be caught

Normally, Lua errors or explicit rejections can be caught:

return Promise.new(function(resolve, reject)
	reject("Test")
end)
:catch(function(err)
	print("Caught", err)
end)

but if using Promise.all, the rejection is never caught:

return Promise.all({function(resolve, reject)
	reject("Test")
end})
:catch(function(err)
	print("Caught", err)
end)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.