Skip to content

Commit 06fc407

Browse files
committed
Update docs for v4
1 parent 893c43a commit 06fc407

File tree

4 files changed

+72
-18
lines changed

4 files changed

+72
-18
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Changelog
22

3+
## [4.0.0-rc.1] - 2021-12-28
4+
### Changed
5+
- `Promise:finally` no longer observes a rejection from a Promise. Calling `Promise:finally` is mostly transparent now.
6+
- The Promise returned by `Promise:finally` resolves or rejects with whatever the parent Promise resolved or rejected with. It will be cancelled if the parent Promise is cancelled.
7+
- The value returned from the `finally` handler is discarded now.
8+
- If the value returned from the `finally` handler is a Promise, we wait for it to resolve, but we do not use its value.
9+
- If the value returned from the `finally` handler is a Promise and it rejects, `finally` returns the new rejected value.
10+
- `Promise:finally` no longer counts as a consumer of the parent Promise for cancellation purposes. If all consumers are cancelled and the only remaining callbacks are finally handlers, the Promise is now cancelled.
11+
- The Promise executor thread is now closed with `coroutine.close` when the Promise is cancelled.
12+
- The Promise executor thread is now closed after the Promise settles (calling `resolve` or `reject`).
13+
- Callbacks enqueued with `andThen` and `catch` are now dequeued if the Promise returned by `andThen`/`catch` is cancelled.
14+
- Calling `andThen` or `catch` on an already-cancelled Promise now returns a cancelled Promise instead of returning a rejected Promise
15+
- `:await`, `:expect`, and `:awaitStatus` are no longer backed by BindableEvents, and now use the task library directly, so performance should be better.
16+
17+
### Removed
18+
- `Promise:done` and its associated members have been removed.
19+
320
## [3.2.0] - 2021-12-27
421
### Added
522
- Add `Promise.onUnhandledRejection` global event

docs/Examples.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,7 @@ end
5252
## Cancellable animation sequence
5353
The following is an example of an animation sequence which is composable and cancellable. If the sequence is cancelled, the animated part will instantly jump to the end position as if it had played all the way through.
5454

55-
We use [Promise.doneCall](/api/Promise#doneCall), which uses `done` internally, instead of `andThen` because we want the Promises to run even if the Promise is cancelled. We handle the case of the Promise being cancelled with the `onCancel` function.
56-
57-
We take advantage of Promise chaining by returning Promises from the `done` handler functions. Because of this behavior, cancelling the final Promise in the chain will propagate up to the very top and cancel every single Promise you see here.
55+
We take advantage of Promise chaining by returning Promises from the `finally` handler functions. Because of this behavior, cancelling the final Promise in the chain will propagate up to the very top and cancel every single Promise you see here.
5856

5957
```lua
6058
local Promise = require(game.ReplicatedStorage.Promise)
@@ -84,23 +82,23 @@ end
8482

8583
local function runAnimation(part, intensity)
8684
return Promise.resolve()
87-
:doneCall(sleep, 1)
88-
:doneCall(runTween, part, {
85+
:finallyCall(sleep, 1)
86+
:finallyCall(runTween, part, {
8987
Reflectance = 1 * intensity
90-
}):doneCall(runTween, part, {
88+
}):finallyCall(runTween, part, {
9189
CFrame = CFrame.new(part.Position) *
9290
CFrame.Angles(0, math.rad(90 * intensity), 0)
93-
}):doneCall(runTween, part, {
91+
}):finallyCall(runTween, part, {
9492
Size = (
9593
Vector3.new(10, 10, 10) * intensity
9694
) + Vector3.new(1, 1, 1)
9795
})
9896
end
9997

10098
local animation = Promise.resolve() -- Begin Promise chain
101-
:doneCall(runAnimation, workspace.Part, 1)
102-
:doneCall(sleep, 1)
103-
:doneCall(runAnimation, workspace.Part, 0)
99+
:finallyCall(runAnimation, workspace.Part, 1)
100+
:finallyCall(sleep, 1)
101+
:finallyCall(runAnimation, workspace.Part, 0)
104102
:catch(warn)
105103

106104
wait(2)

docs/Tour.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ It's good practice to add an `onCancel` hook to all of your asynchronous Promise
160160
Even if you don't plan to directly cancel a particular Promise, chaining with other Promises can cause it to become automatically cancelled if no one cares about the value anymore.
161161
:::
162162

163-
If you attach a `:andThen` or `:catch` handler to a Promise after it's been cancelled, the chained Promise will be instantly rejected with `Promise.Error(Promise.Error.Kind.AlreadyCancelled)`. This also applies to Promises that you pass to `resolve`. However, `finally` does not have this constraint.
163+
If you attach a `:andThen` or `:catch` handler to a Promise after it's been cancelled, the chained Promise will be cancelled as well. This also applies to Promises that you pass to `resolve`.
164164

165165
:::warning
166166
If you cancel a Promise immediately after creating it without yielding in between, the fate of the Promise is dependent on if the Promise handler yields or not. If the Promise handler resolves without yielding, then the Promise will already be settled by the time you are able to cancel it, thus any consumers of the Promise will have already been called and cancellation is not possible.

lib/init.lua

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,12 @@ end
337337
* You can set the cancellation hook at any time before resolving.
338338
* When a promise is cancelled, calls to `resolve` or `reject` will be ignored, regardless of if you set a cancellation hook or not.
339339
340+
:::caution
341+
If the Promise is cancelled, the `executor` thread is closed with `coroutine.close` after the cancellation hook is called.
342+
343+
You must perform any cleanup code in the cancellation hook: any time your executor yields, it **may never resume**.
344+
:::
345+
340346
@param executor (resolve: (...: any) -> (), reject: (...: any) -> (), onCancel: (abortHandler?: () -> ()) -> boolean) -> ()
341347
@return Promise
342348
]=]
@@ -1258,7 +1264,15 @@ end
12581264
Within the failure handler, you should never assume that the rejection value is a string. Some rejections within the Promise library are represented by [[Error]] objects. If you want to treat it as a string for debugging, you should call `tostring` on it first.
12591265
:::
12601266
1261-
Return a Promise from the success or failure handler and it will be chained onto.
1267+
You can return a Promise from the success or failure handler and it will be chained onto.
1268+
1269+
Calling `andThen` on a cancelled Promise returns a cancelled Promise.
1270+
1271+
:::tip
1272+
If the Promise returned by `andThen` is cancelled, `successHandler` and `failureHandler` will not run.
1273+
1274+
To run code no matter what, use [Promise:finally].
1275+
:::
12621276
12631277
@param successHandler (...: any) -> ...any
12641278
@param failureHandler? (...: any) -> ...any
@@ -1280,6 +1294,13 @@ end
12801294
Within the failure handler, you should never assume that the rejection value is a string. Some rejections within the Promise library are represented by [[Error]] objects. If you want to treat it as a string for debugging, you should call `tostring` on it first.
12811295
:::
12821296
1297+
Calling `catch` on a cancelled Promise returns a cancelled Promise.
1298+
1299+
:::tip
1300+
If the Promise returned by `catch` is cancelled, `failureHandler` will not run.
1301+
1302+
To run code no matter what, use [Promise:finally].
1303+
:::
12831304
12841305
@param failureHandler (...: any) -> ...any
12851306
@return Promise<...any>
@@ -1485,12 +1506,30 @@ function Promise.prototype:_finally(traceback, finallyHandler)
14851506
end
14861507

14871508
--[=[
1488-
Set a handler that will be called regardless of the promise's fate. The handler is called when the promise is resolved, rejected, *or* cancelled.
1489-
1490-
Returns a new promise chained from this promise.
1491-
1492-
:::caution
1493-
If the Promise is cancelled, any Promises chained off of it with `andThen` won't run. Only Promises chained with `finally` or `done` will run in the case of cancellation.
1509+
Set a handler that will be called regardless of the promise's fate. The handler is called when the promise is
1510+
resolved, rejected, *or* cancelled.
1511+
1512+
Returns a new Promise that:
1513+
- resolves with the same values that this Promise resolves with.
1514+
- rejects with the same values that this Promise rejects with.
1515+
- is cancelled if this Promise is cancelled.
1516+
1517+
If the value you return from the handler is a Promise:
1518+
- We wait for the Promise to resolve, but we ultimately discard the resolved value.
1519+
- If the returned Promise rejects, the Promise returned from `finally` will reject with the rejected value from the
1520+
*returned* promise.
1521+
- If the `finally` Promise is cancelled, and you returned a Promise from the handler, we cancel that Promise too.
1522+
1523+
Otherwise, the return value from the `finally` handler is entirely discarded.
1524+
1525+
:::note Cancellation
1526+
As of Promise v4, `Promise:finally` does not count as a consumer of the parent Promise for cancellation purposes.
1527+
This means that if all of a Promise's consumers are cancelled and the only remaining callbacks are finally handlers,
1528+
the Promise is cancelled and the finally callbacks run then and there.
1529+
1530+
Cancellation still propagates through the `finally` Promise though: if you cancel the `finally` Promise, it can cancel
1531+
its parent Promise if it had no other consumers. Likewise, if the parent Promise is cancelled, the `finally` Promise
1532+
will also be cancelled.
14941533
:::
14951534
14961535
```lua

0 commit comments

Comments
 (0)