fromEventPattern is not a good replacement for 'forEvent' operator #7527
hansschenker
started this conversation in
Ideas / Feature request
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Why Keeping fromEvent Could Be a Good Idea:
Consistency: A single operator with different behaviors based on parameters is a common pattern in functional programming. This way, you don't need multiple operators like fromEvent, fromCallback, and fromNodeCallback; you can just use one operator with different strategies based on how you configure it.
Behavior-Based Design: By keeping one operator, you let the behavior of the operator be controlled by its input parameters, instead of making users choose between multiple operators. This leads to a more flexible and composable design, where the functionality adapts to the use case via arguments, rather than requiring different operator names for different scenarios.
Simpler API: From a consumer's perspective, having one operator (fromEvent) with the ability to handle various event sources, callbacks, or Node.js callbacks makes it easier to understand and use the API without needing to remember which operator to use in which case. It reduces the cognitive load and keeps the API surface smaller.
How fromEvent Could Internally Manage Strategies:
Here's how RxJS could manage different strategies for callback and Node.js-style callback internally in the fromEvent operator, using different parameters.
Example for Managing Callback and Node.js Callback Internally:
ts
Copy
import { fromEvent } from 'rxjs';
// Standard Event Listener (e.g., DOM events)
const click$ = fromEvent(document, 'click');
// Node.js-style callback (using a callback API)
const fileRead$ = fromEvent(
fs.readFile, // Node.js function
'data', // Event name for stream
(callback: (err: Error, data: string) => void) => {
// Wrap callback in a function
callback(null, 'file data');
}
);
// Callback-style API (e.g., traditional callback functions)
const fetchData$ = fromEvent(
fetchDataAPI, // A function that accepts a callback
'dataReceived', // Custom event name for the callback
(callback: (result: string) => void) => {
callback('Some data received');
}
);
Parameters:
First Parameter: The function that either attaches an event listener (for DOM events) or registers a callback (for callback-based APIs or Node.js callbacks).
Second Parameter: The event name, which could be a DOM event name like 'click', or a custom event name for callback-based APIs (like 'dataReceived' for a callback API).
Third Parameter (Optional): A function that transforms the callback behavior (or handles unsubscription cleanup), for example, wrapping a callback in a Node.js callback or allowing custom transformations of the emitted values.
The Benefit of This Approach:
Unified Logic: The operator itself (fromEvent) would remain unified, but its behavior would change based on the type of event source or callback mechanism passed. This means fromEvent could adapt to different APIs seamlessly by checking the type of the event source and the parameters provided.
Flexibility: This approach gives users the flexibility to handle different event-driven APIs (DOM, callback-based, or Node.js-style) without introducing new operators for each type of event. You can simply apply different behaviors based on the needs of the API you're working with.
Haskell-Style Type Signature (with internal strategies):
haskell
Copy
fromEvent :: (EventTarget -> EventListener -> IO ()) -- for EventTarget-based APIs like DOM
-> (CallbackFunction -> IO ()) -- for callback APIs
-> (NodeCallbackFunction -> IO ()) -- for Node.js-style callbacks
-> Observable a
How This Aligns with Functional Programming:
First-class functions: By using functions like addHandler and removeHandler, you're treating behavior as first-class, meaning you can easily compose or swap strategies based on context.
Composability: This approach allows RxJS users to focus on composing behaviors for different event types rather than learning and managing separate operators.
Parameterization over name proliferation: It avoids proliferation of operator names by using parameterization to define which behavior (callback, event listener, or Node.js-style callback) should be used. This makes the API more elegant and functional in its design.
Conclusion:
Keeping fromEvent as the central operator and managing internal strategies based on parameters would definitely align with the functional programming principles of abstraction, flexibility, and composability. It would allow RxJS to provide a clean, unified API that adapts its behavior based on the given input, minimizing unnecessary complexity. This makes the operator more intuitive and expressive, adhering to the idea that the behavior of the operator changes based on the parameters applied, which is a key concept in functional programming.
Beta Was this translation helpful? Give feedback.
All reactions