mirror of
https://github.com/AmberGraceRblx/luau-promise.git
synced 2025-04-24 15:50:01 +00:00
Implement Promise.all (#4)
This commit is contained in:
parent
e6b43a1fae
commit
371f08598c
3 changed files with 111 additions and 4 deletions
|
@ -25,6 +25,11 @@ This Promise implementation attempts to satisfy those traits.
|
|||
* 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`
|
||||
|
@ -69,8 +74,6 @@ httpGet("https://google.com")
|
|||
```
|
||||
|
||||
## Future Additions
|
||||
* `Promise.all`
|
||||
* Currently stubbed out, throws an error.
|
||||
* `Promise.wrapAsync`
|
||||
* Intended to wrap an existing Roblox API that yields, exposing a new one that returns a Promise.
|
||||
|
||||
|
|
56
lib/init.lua
56
lib/init.lua
|
@ -165,8 +165,60 @@ end
|
|||
* is resolved when all input promises resolve
|
||||
* is rejected if ANY input promises reject
|
||||
]]
|
||||
function Promise.all(...)
|
||||
error("unimplemented", 2)
|
||||
function Promise.all(promises)
|
||||
if type(promises) ~= "table" then
|
||||
error("Please pass an array of promises or values to Promise.all", 2)
|
||||
end
|
||||
|
||||
-- If there are no values then return an already resolved promise.
|
||||
if #promises == 0 then
|
||||
return Promise.resolve({})
|
||||
end
|
||||
|
||||
-- We need to check that each value is a promise here so that we can produce a
|
||||
-- proper error rather than a rejected promise with our error.
|
||||
for i = 1, #promises do
|
||||
if not Promise.is(promises[i]) then
|
||||
error(("Non-promise value passed into Promise.all at index #%d"):format(i), 2)
|
||||
end
|
||||
end
|
||||
|
||||
return Promise.new(function(resolve, reject)
|
||||
-- An array to contain our resolved values from the given promises.
|
||||
local resolvedValues = {}
|
||||
-- Keep a count of resolved promises because just checking the resolved values length
|
||||
-- wouldn't account for promises that resolve with nil.
|
||||
local resolvedCount = 0
|
||||
local rejected = false
|
||||
|
||||
-- Called when a single value is resolved and resolves if all are done.
|
||||
local function resolveOne(i, ...)
|
||||
if rejected then
|
||||
-- Bail out if this promise has already been rejected.
|
||||
return
|
||||
end
|
||||
|
||||
resolvedValues[i] = ...
|
||||
resolvedCount = resolvedCount + 1
|
||||
|
||||
if resolvedCount == #promises then
|
||||
resolve(resolvedValues)
|
||||
end
|
||||
end
|
||||
|
||||
-- We can assume the values inside `promises` are all promises since we checked above.
|
||||
for i = 1, #promises do
|
||||
promises[i]:andThen(function(...)
|
||||
resolveOne(i, ...)
|
||||
end)
|
||||
:catch(function(...)
|
||||
-- Only reject if this promise is unrejected.
|
||||
if not rejected then
|
||||
reject(...)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--[[
|
||||
|
|
|
@ -264,4 +264,56 @@ return function()
|
|||
expect(#chained._values).to.equal(0)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("Promise.all", function()
|
||||
it("should error if given something other than a table", function()
|
||||
expect(function()
|
||||
Promise.all(1)
|
||||
end).to.throw()
|
||||
end)
|
||||
|
||||
it("should resolve instantly with an empty table if given no values", function()
|
||||
local promise = Promise.all({})
|
||||
local success, value = promise:await()
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
|
||||
expect(value).to.be.a("table")
|
||||
expect(#value).to.equal(0)
|
||||
end)
|
||||
|
||||
it("should error if given non-promise values", function()
|
||||
expect(function()
|
||||
Promise.all({{}, {}, {}})
|
||||
end).to.throw()
|
||||
end)
|
||||
|
||||
it("should wait for all promises to be resolved and return their values", function()
|
||||
local promises = {
|
||||
Promise.new(function(resolve)
|
||||
resolve(1)
|
||||
end),
|
||||
Promise.new(function(resolve)
|
||||
resolve("A string")
|
||||
end),
|
||||
Promise.new(function(resolve)
|
||||
resolve(nil)
|
||||
end),
|
||||
Promise.new(function(resolve)
|
||||
resolve(false)
|
||||
end)
|
||||
}
|
||||
|
||||
local promise = Promise.all(promises)
|
||||
local success, resolved = promise:await()
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(resolved).to.be.a("table")
|
||||
expect(#resolved).to.equal(4)
|
||||
expect(resolved[1]).to.equal(1)
|
||||
expect(resolved[2]).to.equal("A string")
|
||||
expect(resolved[3]).to.equal(nil)
|
||||
expect(resolved[4]).to.equal(false)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue