mirror of
https://github.com/AmberGraceRblx/luau-promise.git
synced 2025-04-24 15:50:01 +00:00
commit
48d756b6d6
4 changed files with 149 additions and 27 deletions
|
@ -1,5 +1,10 @@
|
|||
# Changelog
|
||||
|
||||
## Unreleased changes
|
||||
|
||||
### Added
|
||||
- Added `Promise.fold` (#47)
|
||||
|
||||
## [3.0.1] - 2020-08-24
|
||||
### Fixed
|
||||
- Make `Promise.is` work with promises from old versions of the library (#41)
|
||||
|
|
|
@ -356,6 +356,41 @@ docs:
|
|||
returns: Promise<number>
|
||||
static: true
|
||||
|
||||
- name: fold
|
||||
since: unreleased
|
||||
desc: |
|
||||
Folds an array of values or promises into a single value. The array is traversed sequentially.
|
||||
|
||||
The reducer function can return a promise or value directly. Each iteration receives the resolved value from the previous, and the first receives your defined initial value.
|
||||
|
||||
The folding will stop at the first rejection encountered.
|
||||
```lua
|
||||
local basket = {"blueberry", "melon", "pear", "melon"}
|
||||
Promise.fold(basket, function(cost, fruit)
|
||||
if fruit == "blueberry" then
|
||||
return cost -- blueberries are free!
|
||||
else
|
||||
-- call a function that returns a promise with the fruit price
|
||||
return fetchPrice(fruit):andThen(function(fruitCost)
|
||||
return cost + fruitCost
|
||||
end)
|
||||
end
|
||||
end, 0)
|
||||
```
|
||||
params:
|
||||
- name: list
|
||||
type: "array<T | Promise<T>>"
|
||||
- name: reducer
|
||||
desc: The function to call with the accumulated value, the current element from the array and its index.
|
||||
type:
|
||||
kind: function
|
||||
params: "accumulator: U, value: T, index: number"
|
||||
returns: U | Promise<U>
|
||||
- name: initialValue
|
||||
type: "U"
|
||||
returns: Promise<U>
|
||||
static: true
|
||||
|
||||
- name: each
|
||||
since: 3.0.0
|
||||
desc: |
|
||||
|
|
12
lib/init.lua
12
lib/init.lua
|
@ -439,6 +439,18 @@ function Promise.all(promises)
|
|||
return Promise._all(debug.traceback(nil, 2), promises)
|
||||
end
|
||||
|
||||
function Promise.fold(list, callback, initialValue)
|
||||
assert(type(list) == "table", "Bad argument #1 to Promise.fold: must be a table")
|
||||
assert(type(callback) == "function", "Bad argument #2 to Promise.fold: must be a function")
|
||||
|
||||
local accumulator = Promise.resolve(initialValue)
|
||||
return Promise.each(list, function(resolvedElement, i)
|
||||
accumulator = accumulator:andThen(function(previousValueResolved)
|
||||
return callback(previousValueResolved, resolvedElement, i)
|
||||
end)
|
||||
end):andThenReturn(accumulator)
|
||||
end
|
||||
|
||||
function Promise.some(promises, amount)
|
||||
assert(type(amount) == "number", "Bad argument #2 to Promise.some: must be a number")
|
||||
|
||||
|
|
|
@ -811,6 +811,76 @@ return function()
|
|||
end)
|
||||
end)
|
||||
|
||||
describe("Promise.fold", function()
|
||||
it("should return the initial value in a promise when the list is empty", function()
|
||||
local initialValue = {}
|
||||
local result = Promise.fold({}, function()
|
||||
error("should not be called")
|
||||
end, initialValue)
|
||||
|
||||
expect(Promise.is(result)).to.equal(true)
|
||||
expect(result:getStatus()).to.equal(Promise.Status.Resolved)
|
||||
expect(result:expect()).to.equal(initialValue)
|
||||
end)
|
||||
|
||||
it("should accept promises in the list", function()
|
||||
local sum = Promise.fold({Promise.resolve(1), 2, 3}, function(sum, element)
|
||||
return sum + element
|
||||
end, 0)
|
||||
expect(Promise.is(sum)).to.equal(true)
|
||||
expect(sum:getStatus()).to.equal(Promise.Status.Resolved)
|
||||
expect(sum:expect()).to.equal(6)
|
||||
end)
|
||||
|
||||
it("should always return a promise even if the list or reducer don't use them", function()
|
||||
local sum = Promise.fold({1, 2, 3}, function(sum, element, index)
|
||||
if index == 2 then
|
||||
return Promise.delay(1):andThenReturn(sum + element)
|
||||
else
|
||||
return sum + element
|
||||
end
|
||||
end, 0)
|
||||
expect(Promise.is(sum)).to.equal(true)
|
||||
expect(sum:getStatus()).to.equal(Promise.Status.Started)
|
||||
advanceTime(2)
|
||||
expect(sum:getStatus()).to.equal(Promise.Status.Resolved)
|
||||
expect(sum:expect()).to.equal(6)
|
||||
end)
|
||||
|
||||
it("should return the first rejected promise", function()
|
||||
local errorMessage = "foo"
|
||||
local sum = Promise.fold({1, 2, 3}, function(sum, element, index)
|
||||
if index == 2 then
|
||||
return Promise.reject(errorMessage)
|
||||
else
|
||||
return sum + element
|
||||
end
|
||||
end, 0)
|
||||
expect(Promise.is(sum)).to.equal(true)
|
||||
local status, rejection = sum:awaitStatus()
|
||||
expect(status).to.equal(Promise.Status.Rejected)
|
||||
expect(rejection).to.equal(errorMessage)
|
||||
end)
|
||||
|
||||
it("should return the first canceled promise", function()
|
||||
local secondPromise
|
||||
local sum = Promise.fold({1, 2, 3}, function(sum, element, index)
|
||||
if index == 1 then
|
||||
return sum + element
|
||||
elseif index == 2 then
|
||||
secondPromise = Promise.delay(1):andThenReturn(sum + element)
|
||||
return secondPromise
|
||||
else
|
||||
error('this should not run if the promise is cancelled')
|
||||
end
|
||||
end, 0)
|
||||
expect(Promise.is(sum)).to.equal(true)
|
||||
expect(sum:getStatus()).to.equal(Promise.Status.Started)
|
||||
secondPromise:cancel()
|
||||
expect(sum:getStatus()).to.equal(Promise.Status.Cancelled)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("Promise.race", function()
|
||||
it("should resolve with the first settled value", function()
|
||||
local promise = Promise.race({
|
||||
|
|
Loading…
Reference in a new issue