Tomorrowland v1.4.0 Release Notes

Release Date: 2020-07-28 // over 1 year ago

    ๐Ÿ›  Fix the cancellation propagation behavior of Promise.Resolver.resolve(with:) and the flatMap family of methods. Previously, requesting cancellation of the promise associated with the resolver (for resolve(with:), or the returned promise for the flatMap family) would immediately request cancellation of the upstream promise even if the upstream promise had other children. The new behavior fixes this such that it participates in automatic cancellation propagation just like any other child promise (#54).

    โšก๏ธ Slightly optimize stack usage when chaining one promise to another.

    Avoid using stack space for chained promises that don't involve a callback. For example, when the promise returned from a flatMap(on:token:_:) resolves it will resolve the outer promise without using additional stack frames. You can think of it like tail calling functions. This affects not just flatMap but also operations such as tap(), ignoringCancel(), and more. This also applies to Obj-C (with TWLPromise).

    Note: This does not affect the variants that implicitly upcast from some E: Swift.Error to Swift.Error such as tryFlatMap(on:token:_:).

    ๐Ÿ”„ Change cancellation propagation behavior of onCancel. Like tap, it doesn't prevent automatic cancellation propagation if the parent has other children and all other children request cancellation. Unlike tap, requesting cancellation of onCancel when there are no other children will propagate cancellation to the parent. The motivation here is attaching an onCancel observer shouldn't prevent cancellation that would otherwise occur, but when it's the only child it should behave like the other standard observers (#57).

    โž• Add method Promise.makeChild(). This returns a new child of the receiver that adopts the receiver's value and propagates cancellation like any other observer. The purpose here is to be used when handing back multiple children of one parent to callers, as handing back the parent means any one caller can cancel it without the other callers' participation. This is particularly useful in conjunction with propagatingCancellation(on:cancelRequested:) (#56).


Previous changes from v1.3.0

    • ๐Ÿ”€ Add PromiseContext.isExecutingNow (TWLPromiseContext.isExecutingNow in Obj-C) that returns true if accessed from within a callback registered with .nowOr(_:) and executing synchronously, or false otherwise. If accessed from within a callback (or Promise.init(on:_:)) registered with .immediate and running synchronously, it inherits the surrounding scope's PromiseContext.isExecutingNow flag. This is intended to allow Promise(on: .immediate, { โ€ฆ }) to query the surrounding scope's flag (#53).
    • โž• Add convenience methods to Obj-C for doing then+catch together, as this is a common pattern and chaining Obj-C methods is a little awkward (#45).
    • ๐Ÿ”„ Change Promise.timeout's default context to .nowOr(.auto) for the Error overload as well.
    • ๐Ÿ”„ Change the behavior of Promise.timeout(on:delay:) when the delay is less than or equal to zero, the context is .immediate or .nowOr(_:), and the upstream promise hasn't resolved yet. Previously the timeout would occur asynchronously and the upstream promise would get a chance to race the timeout. With the new behavior the timeout occurs synchronously (#49).