Add Return and done

Closes #9
This commit is contained in:
Eryn Lynn 2019-09-28 22:03:06 -04:00
parent 3052ec1474
commit bb13a0e2b6
4 changed files with 267 additions and 2 deletions

View file

@ -8,6 +8,8 @@
- Improve stack traces - Improve stack traces
- Promise.promisify will now turn errors into rejections even if they occur after a yield. - Promise.promisify will now turn errors into rejections even if they occur after a yield.
- Add Promise.try - Add Promise.try
- Add `done`, `doneCall`, `doneReturn`
- Add `andThenReturn`, `finallyReturn`
# 2.4.0 # 2.4.0

View file

@ -322,6 +322,31 @@ docs:
returns: Promise<T> returns: Promise<T>
returns: Promise<T> returns: Promise<T>
- name: done
desc: |
Set a handler that will be called only if the Promise resolves or is cancelled. This method is similar to `finally`, except it doesn't catch rejections.
::: warning
If this Promise is cancelled, any Promises chained off of it with `andThen` won't run. Only Promises chained with `done` and `finally` will run in the case of cancellation.
:::
Returns a new promise chained from this promise.
params:
- name: doneHandler
type:
kind: function
params: "status: PromiseStatus"
returns: ...any?
returns: Promise<...any?>
overloads:
- params:
- name: doneHandler
type:
kind: function
params: "status: PromiseStatus"
returns: Promise<T>
returns: Promise<T>
- name: andThenCall - name: andThenCall
desc: | desc: |
Attaches an `andThen` handler to this Promise that calls the given callback with the predefined arguments. The resolved value is discarded. Attaches an `andThen` handler to this Promise that calls the given callback with the predefined arguments. The resolved value is discarded.
@ -364,6 +389,87 @@ docs:
desc: Arguments which will be passed to the callback. desc: Arguments which will be passed to the callback.
returns: Promise returns: Promise
- name: doneCall
desc: |
Same as `andThenCall`, except for `done`.
Attaches a `done` handler to this Promise that calls the given callback with the predefined arguments.
params:
- name: callback
type:
kind: function
params: "...: ...any?"
returns: "any"
- name: "..."
type: "...any?"
desc: Arguments which will be passed to the callback.
returns: Promise
- name: andThenReturn
desc: |
Attaches an `andThen` handler to this Promise that discards the resolved value and returns the given value from it.
```lua
promise:andThenReturn("some", "values")
```
This is sugar for
```lua
promise:andThen(function()
return "some", "values"
end)
```
params:
- name: "..."
type: "...any?"
desc: Values to return from the function.
returns: Promise<...any?>
- name: finallyReturn
desc: |
Attaches a `finally` handler to this Promise that discards the resolved value and returns the given value from it.
```lua
promise:finallyReturn("some", "values")
```
This is sugar for
```lua
promise:finally(function()
return "some", "values"
end)
```
params:
- name: "..."
type: "...any?"
desc: Values to return from the function.
returns: Promise<...any?>
- name: doneReturn
desc: |
Attaches a `done` handler to this Promise that discards the resolved value and returns the given value from it.
```lua
promise:doneReturn("some", "values")
```
This is sugar for
```lua
promise:done(function()
return "some", "values"
end)
```
params:
- name: "..."
type: "...any?"
desc: Values to return from the function.
returns: Promise<...any?>
- name: cancel - name: cancel
desc: | desc: |
Cancels this promise, preventing the promise from resolving or rejecting. Does not do anything if the promise is already settled. Cancels this promise, preventing the promise from resolving or rejecting. Does not do anything if the promise is already settled.

View file

@ -502,6 +502,16 @@ function Promise.prototype:andThenCall(callback, ...)
end) end)
end end
--[[
Shorthand for an andThen handler that returns the given value.
]]
function Promise.prototype:andThenReturn(...)
local length, values = pack(...)
return self:_andThen(debug.traceback(), function()
return unpack(values, 1, length)
end)
end
--[[ --[[
Cancels the promise, disallowing it from rejecting or resolving, and calls Cancels the promise, disallowing it from rejecting or resolving, and calls
the cancellation hook if provided. the cancellation hook if provided.
@ -548,8 +558,10 @@ end
Used to set a handler for when the promise resolves, rejects, or is Used to set a handler for when the promise resolves, rejects, or is
cancelled. Returns a new promise chained from this promise. cancelled. Returns a new promise chained from this promise.
]] ]]
function Promise.prototype:_finally(traceback, finallyHandler) function Promise.prototype:_finally(traceback, finallyHandler, onlyOk)
self._unhandledRejection = false if not onlyOk then
self._unhandledRejection = false
end
-- Return a promise chained off of this promise -- Return a promise chained off of this promise
return Promise._new(traceback, function(resolve, reject) return Promise._new(traceback, function(resolve, reject)
@ -563,6 +575,17 @@ function Promise.prototype:_finally(traceback, finallyHandler)
) )
end end
if onlyOk then
local callback = finallyCallback
finallyCallback = function(...)
if self._status == Promise.Status.Rejected then
return resolve(self)
end
return callback(...)
end
end
if self._status == Promise.Status.Started then if self._status == Promise.Status.Started then
-- The promise is not settled, so queue this. -- The promise is not settled, so queue this.
table.insert(self._queuedFinally, finallyCallback) table.insert(self._queuedFinally, finallyCallback)
@ -592,6 +615,48 @@ function Promise.prototype:finallyCall(callback, ...)
end) end)
end end
--[[
Shorthand for a finally handler that returns the given value.
]]
function Promise.prototype:finallyReturn(...)
local length, values = pack(...)
return self:_finally(debug.traceback(), function()
return unpack(values, 1, length)
end)
end
--[[
Similar to finally, except rejections are propagated through it.
]]
function Promise.prototype:done(finallyHandler)
assert(
finallyHandler == nil or type(finallyHandler) == "function",
ERROR_NON_FUNCTION:format("Promise:finallyO")
)
return self:_finally(debug.traceback(), finallyHandler, true)
end
--[[
Calls a callback on `done` with specific arguments.
]]
function Promise.prototype:doneCall(callback, ...)
assert(type(callback) == "function", ERROR_NON_FUNCTION:format("Promise:doneCall"))
local length, values = pack(...)
return self:_finally(debug.traceback(), function()
return callback(unpack(values, 1, length))
end, true)
end
--[[
Shorthand for a done handler that returns the given value.
]]
function Promise.prototype:doneReturn(...)
local length, values = pack(...)
return self:_finally(debug.traceback(), function()
return unpack(values, 1, length)
end, true)
end
--[[ --[[
Yield until the promise is completed. Yield until the promise is completed.

View file

@ -416,6 +416,18 @@ return function()
expect(p2._parent).to.equal(p1) expect(p2._parent).to.equal(p1)
expect(p1._consumers[p2]).to.equal(true) expect(p1._consumers[p2]).to.equal(true)
end) end)
it("should forward return values", function()
local value
Promise.resolve():finally(function()
return 1
end):andThen(function(v)
value = v
end)
expect(value).to.equal(1)
end)
end) end)
describe("Promise.all", function() describe("Promise.all", function()
@ -698,4 +710,84 @@ return function()
expect(errorText:find("errortext")).to.be.ok() expect(errorText:find("errortext")).to.be.ok()
end) end)
end) end)
describe("Promise:andThenReturn", function()
it("should return the given values", function()
local value1, value2
Promise.resolve():andThenReturn(1, 2):andThen(function(one, two)
value1 = one
value2 = two
end)
expect(value1).to.equal(1)
expect(value2).to.equal(2)
end)
end)
describe("Promise:doneReturn", function()
it("should return the given values", function()
local value1, value2
Promise.resolve():doneReturn(1, 2):andThen(function(one, two)
value1 = one
value2 = two
end)
expect(value1).to.equal(1)
expect(value2).to.equal(2)
end)
end)
describe("Promise:andThenCall", function()
it("should call the given function with arguments", function()
local value1, value2
Promise.resolve():andThenCall(function(a, b)
value1 = a
value2 = b
end, 3, 4)
expect(value1).to.equal(3)
expect(value2).to.equal(4)
end)
end)
describe("Promise:doneCall", function()
it("should call the given function with arguments", function()
local value1, value2
Promise.resolve():doneCall(function(a, b)
value1 = a
value2 = b
end, 3, 4)
expect(value1).to.equal(3)
expect(value2).to.equal(4)
end)
end)
describe("Promise:done", function()
it("should trigger on resolve or cancel", function()
local promise = Promise.new(function() end)
local value
local p = promise:done(function()
value = true
end)
expect(value).to.never.be.ok()
promise:cancel()
expect(p:getStatus()).to.equal(Promise.Status.Cancelled)
expect(value).to.equal(true)
local never, always
Promise.reject():done(function()
never = true
end):finally(function()
always = true
end)
expect(never).to.never.be.ok()
expect(always).to.be.ok()
end)
end)
end end