Skip to content

promises 1.4.0

Choose a tag to compare

@schloerke schloerke released this 22 Oct 14:03
e6b0992

Breaking changes

  • Nested promise domains now correctly invoke in reverse order. Previously, when promise domains were nested, the outer domain would incorrectly take precedence over the inner domain in wrapOnFulfilled/wrapOnRejected callbacks. The innermost (most recently added) domain now properly wraps the callback first, ensuring that nested promise domains behave consistently with the expected scoping behavior. (#165)

New features

  • hybrid_then() synchronously or asynchronously executes success/failure callbacks based on whether the input is a promise or a regular value. This function is useful for writing code that can handle both synchronous and asynchronous inputs seamlessly. (#192)

  • then() gains a tee parameter. When tee = TRUE, then() ignores the return value of the callback and returns the original value instead. This is useful for performing operations with side-effects, particularly logging to the console or a file. finally() does not support tee as the return value is always ignored. (#148)

OpenTelemetry integration

promises now integrates with the otel package to provide observability and tracing for asynchronous operations. OpenTelemetry integration is experimental and subject to change.

  • with_ospan_async() creates an OpenTelemetry span, executes the given expression within it, and ends the span. This function handles both synchronous and asynchronous (promise-based) operations. For promises, the span is automatically ended when the promise resolves or rejects. To access the OpenTelemetry span within your expression, use otel::get_current_span(). (#173)

  • with_ospan_promise_domain() creates a promise domain that restores the currently active OpenTelemetry span from when a call to then() is executed. This enables proper tracing context across asynchronous operations. (#173)

  • local_ospan_promise_domain() adds an OpenTelemetry span promise domain to the local scope. This is useful for {coro} operations where encapsulating the coro operations inside with_*() methods is not allowed. (#179)

Minor improvements and fixes

  • promises now requires R 4.1 or later. R's native pipe (|>) and function shorthand (\(x) fn(x)) syntax are now preferred over promise pipe methods. The promise pipe methods (%...>%, %...!%, %...T>%) are now superseded in favor of the R syntax supported in R 4.1 or later. (#148)

  • catch() API updated from catch(promise, onRejected, tee = FALSE) to catch(promise, onRejected, ..., tee = FALSE). The tee parameter must now be specified as a keyword argument. (#148)

  • then(tee=) and catch(tee=) now require a logical value (not just a truthy value). (#156)

  • promises is now a pure R package that does not require compilation. We include a test of a C++ interface in inst/promise_task.cpp that is now dynamically compiled during testing. (#154)

  • promise_all() performance improved by using a counter instead of checking completion status of all promises. This changes the time complexity from O(n^2) to O(n) for determining when all promises are complete. (#163)

  • promise_all() now preserves duplicate named arguments (or .list entries). A result will be produced for every promise provided. (#163)

  • promise_map() now properly handles NULL values being returned. (Thank you, @RLesur! #47)

  • promises no longer imports base packages in DESCRIPTION. (Thank you, @shikokuchuo! #186)