1654288680
This proposal introduces an Observable type to the ECMAScript standard library. The Observable type can be used to model push-based data sources such as DOM events, timer intervals, and sockets. In addition, observables are:
Using the Observable constructor, we can create a function which returns an observable stream of events for an arbitrary DOM element and event type.
function listen(element, eventName) {
return new Observable(observer => {
// Create an event handler which sends data to the sink
let handler = event => observer.next(event);
// Attach the event handler
element.addEventListener(eventName, handler, true);
// Return a cleanup function which will cancel the event stream
return () => {
// Detach the event handler from the element
element.removeEventListener(eventName, handler, true);
};
});
}
We can then use standard combinators to filter and map the events in the stream, just like we would with an array.
// Return an observable of special key down commands
function commandKeys(element) {
let keyCommands = { "38": "up", "40": "down" };
return listen(element, "keydown")
.filter(event => event.keyCode in keyCommands)
.map(event => keyCommands[event.keyCode])
}
Note: The "filter" and "map" methods are not included in this proposal. They may be added in a future version of this specification.
When we want to consume the event stream, we subscribe with an observer.
let subscription = commandKeys(inputElement).subscribe({
next(val) { console.log("Received key command: " + val) },
error(err) { console.log("Received an error: " + err) },
complete() { console.log("Stream complete") },
});
The object returned by subscribe will allow us to cancel the subscription at any time. Upon cancelation, the Observable's cleanup function will be executed.
// After calling this function, no more events will be sent
subscription.unsubscribe();
The Observable type represents one of the fundamental protocols for processing asynchronous streams of data. It is particularly effective at modeling streams of data which originate from the environment and are pushed into the application, such as user interface events. By offering Observable as a component of the ECMAScript standard library, we allow platforms and applications to share a common push-based stream protocol.
To run the unit tests, install the es-observable-tests package into your project.
npm install es-observable-tests
Then call the exported runTests
function with the constructor you want to test.
require("es-observable-tests").runTests(MyObservable);
An Observable represents a sequence of values which may be observed.
interface Observable {
constructor(subscriber : SubscriberFunction);
// Subscribes to the sequence with an observer
subscribe(observer : Observer) : Subscription;
// Subscribes to the sequence with callbacks
subscribe(onNext : Function,
onError? : Function,
onComplete? : Function) : Subscription;
// Returns itself
[Symbol.observable]() : Observable;
// Converts items to an Observable
static of(...items) : Observable;
// Converts an observable or iterable to an Observable
static from(observable) : Observable;
}
interface Subscription {
// Cancels the subscription
unsubscribe() : void;
// A boolean value indicating whether the subscription is closed
get closed() : Boolean;
}
function SubscriberFunction(observer: SubscriptionObserver) : (void => void)|Subscription;
Observable.of
creates an Observable of the values provided as arguments. The values are delivered synchronously when subscribe
is called.
Observable.of("red", "green", "blue").subscribe({
next(color) {
console.log(color);
}
});
/*
> "red"
> "green"
> "blue"
*/
Observable.from
converts its argument to an Observable.
Symbol.observable
method, then it returns the result of invoking that method. If the resulting object is not an instance of Observable, then it is wrapped in an Observable which will delegate subscription.subscribe
is called.Converting from an object which supports Symbol.observable
to an Observable:
Observable.from({
[Symbol.observable]() {
return new Observable(observer => {
setTimeout(() => {
observer.next("hello");
observer.next("world");
observer.complete();
}, 2000);
});
}
}).subscribe({
next(value) {
console.log(value);
}
});
/*
> "hello"
> "world"
*/
let observable = new Observable(observer => {});
Observable.from(observable) === observable; // true
Converting from an iterable to an Observable:
Observable.from(["mercury", "venus", "earth"]).subscribe({
next(value) {
console.log(value);
}
});
/*
> "mercury"
> "venus"
> "earth"
*/
An Observer is used to receive data from an Observable, and is supplied as an argument to subscribe.
All methods are optional.
interface Observer {
// Receives the subscription object when `subscribe` is called
start(subscription : Subscription);
// Receives the next value in the sequence
next(value);
// Receives the sequence error
error(errorValue);
// Receives a completion notification
complete();
}
A SubscriptionObserver is a normalized Observer which wraps the observer object supplied to subscribe.
interface SubscriptionObserver {
// Sends the next value in the sequence
next(value);
// Sends the sequence error
error(errorValue);
// Sends the completion notification
complete();
// A boolean value indicating whether the subscription is closed
get closed() : Boolean;
}
Author: tc39
Source Code: https://github.com/tc39/proposal-observable
License:
1654288680
This proposal introduces an Observable type to the ECMAScript standard library. The Observable type can be used to model push-based data sources such as DOM events, timer intervals, and sockets. In addition, observables are:
Using the Observable constructor, we can create a function which returns an observable stream of events for an arbitrary DOM element and event type.
function listen(element, eventName) {
return new Observable(observer => {
// Create an event handler which sends data to the sink
let handler = event => observer.next(event);
// Attach the event handler
element.addEventListener(eventName, handler, true);
// Return a cleanup function which will cancel the event stream
return () => {
// Detach the event handler from the element
element.removeEventListener(eventName, handler, true);
};
});
}
We can then use standard combinators to filter and map the events in the stream, just like we would with an array.
// Return an observable of special key down commands
function commandKeys(element) {
let keyCommands = { "38": "up", "40": "down" };
return listen(element, "keydown")
.filter(event => event.keyCode in keyCommands)
.map(event => keyCommands[event.keyCode])
}
Note: The "filter" and "map" methods are not included in this proposal. They may be added in a future version of this specification.
When we want to consume the event stream, we subscribe with an observer.
let subscription = commandKeys(inputElement).subscribe({
next(val) { console.log("Received key command: " + val) },
error(err) { console.log("Received an error: " + err) },
complete() { console.log("Stream complete") },
});
The object returned by subscribe will allow us to cancel the subscription at any time. Upon cancelation, the Observable's cleanup function will be executed.
// After calling this function, no more events will be sent
subscription.unsubscribe();
The Observable type represents one of the fundamental protocols for processing asynchronous streams of data. It is particularly effective at modeling streams of data which originate from the environment and are pushed into the application, such as user interface events. By offering Observable as a component of the ECMAScript standard library, we allow platforms and applications to share a common push-based stream protocol.
To run the unit tests, install the es-observable-tests package into your project.
npm install es-observable-tests
Then call the exported runTests
function with the constructor you want to test.
require("es-observable-tests").runTests(MyObservable);
An Observable represents a sequence of values which may be observed.
interface Observable {
constructor(subscriber : SubscriberFunction);
// Subscribes to the sequence with an observer
subscribe(observer : Observer) : Subscription;
// Subscribes to the sequence with callbacks
subscribe(onNext : Function,
onError? : Function,
onComplete? : Function) : Subscription;
// Returns itself
[Symbol.observable]() : Observable;
// Converts items to an Observable
static of(...items) : Observable;
// Converts an observable or iterable to an Observable
static from(observable) : Observable;
}
interface Subscription {
// Cancels the subscription
unsubscribe() : void;
// A boolean value indicating whether the subscription is closed
get closed() : Boolean;
}
function SubscriberFunction(observer: SubscriptionObserver) : (void => void)|Subscription;
Observable.of
creates an Observable of the values provided as arguments. The values are delivered synchronously when subscribe
is called.
Observable.of("red", "green", "blue").subscribe({
next(color) {
console.log(color);
}
});
/*
> "red"
> "green"
> "blue"
*/
Observable.from
converts its argument to an Observable.
Symbol.observable
method, then it returns the result of invoking that method. If the resulting object is not an instance of Observable, then it is wrapped in an Observable which will delegate subscription.subscribe
is called.Converting from an object which supports Symbol.observable
to an Observable:
Observable.from({
[Symbol.observable]() {
return new Observable(observer => {
setTimeout(() => {
observer.next("hello");
observer.next("world");
observer.complete();
}, 2000);
});
}
}).subscribe({
next(value) {
console.log(value);
}
});
/*
> "hello"
> "world"
*/
let observable = new Observable(observer => {});
Observable.from(observable) === observable; // true
Converting from an iterable to an Observable:
Observable.from(["mercury", "venus", "earth"]).subscribe({
next(value) {
console.log(value);
}
});
/*
> "mercury"
> "venus"
> "earth"
*/
An Observer is used to receive data from an Observable, and is supplied as an argument to subscribe.
All methods are optional.
interface Observer {
// Receives the subscription object when `subscribe` is called
start(subscription : Subscription);
// Receives the next value in the sequence
next(value);
// Receives the sequence error
error(errorValue);
// Receives a completion notification
complete();
}
A SubscriptionObserver is a normalized Observer which wraps the observer object supplied to subscribe.
interface SubscriptionObserver {
// Sends the next value in the sequence
next(value);
// Sends the sequence error
error(errorValue);
// Sends the completion notification
complete();
// A boolean value indicating whether the subscription is closed
get closed() : Boolean;
}
Author: tc39
Source Code: https://github.com/tc39/proposal-observable
License:
1603591204
The Observer Pattern is at the core of reactive programming, and observables come in two flavors: hot and cold. This is not explicit when you are coding, so this article explains how to tell the difference and switch to a hot observable. The focus is on hot observables. The concepts here are relevant to all languages that support reactive programming, but the examples are in C#. It’s critical to understand the distinction before you start doing reactive programming because it will bring you unstuck if you don’t.
Please support this blog by signing up for my course Introduction to Uno Platform.
It’s hard to clearly define what Reactive Programming is because it spans so many languages and platforms, and it has overlap with programming constructs like events in C#. I recommend reading through the Wikipedia article because it attempts to give a history of reactive programming and provide objective information.
In a nutshell, reactive programming is about responding to events in the form of sequences (also known as streams) of data. Technically, any programming pattern that deals with this is a form of reactive programming. However, a pattern called the Observer pattern has emerged as the de facto standard for reactive programming. Most programming languages have frameworks for implementing the observer pattern, and the observer pattern has become almost synonymous with reactive programming.
Here are some popular frameworks:
RxJS (JavaScript)
ReactiveUI (.Net)
ReactiveX (Java oriented – with implementations for many platforms)
RxDart (Dart)
The concept is simple. Observables hold information about observers who subscribe to sequences of notifications. The observable is responsible for sending notifications to all of the subscribed observers.
Note: The publish-subscribe (pub/sub pattern) is a closely related pattern, and although technically different, is sometimes used interchangeably with the observer pattern.
Hot observables start producing notifications independently of subscriptions. Cold observables only produce notifications when there are one or more subscriptions.
Take some time to read up about the observer pattern if you are not familiar. If you start Googling, be prepared for many different interpretations of the meaning. This article explains it well and gives examples in C#. This article is another good article on the topic of hot and cold observables.
A hot observable is simpler because only one process runs to generate the notifications, and this process notifies all the observers. A hot observable can start without any subscribed observers and can continue after the last observer unsubscribes.
On the other hand, a cold observable process generally only starts when a subscription occurs and shuts down when the subscription ends. It can run a process for each subscribed observer. This is for more complex use cases.
#.net #c# #reactive programming #software #.net #dart #hot observable #java #javascript #observable #observer pattern #pubsub #reactive #reactiveui
1598380620
Metadata, in a nutshell, is extra information about the actual data. For example, if a variable represents an array, the length of that array is metadata. Similarly, each element in that array is data but the data-type of these elements is metadata. Loosely speaking, metadata is not the actual concern of a program, but it can help us achieve things quicker.
Let’s take a small example. If you need to design a function that prints information about other functions, what information would you print?
(reflect-metadata/func-info.js)
In the above example, the funcInfo
function takes a function as an argument and returns a string that contains function name and the number of arguments this function accepts. This information is contained in the function itself, however, we almost never use that in practice. Therefore, func.name
and func.length
can be considered as metadata.
#nodejs #ecmascript-6 #javascript #ecmascript #es6
1654303800
stream-to-observable
Convert Node Streams into ECMAScript-Observables
Observables
are rapidly gaining popularity. They have much in common with Streams, in that they both represent data that arrives over time. Most Observable implementations provide expressive methods for filtering and mutating incoming data. Methods like .map()
, .filter()
, and .forEach
behave very similarly to their Array counterparts, so using Observables can be very intuitive.
$ npm install --save stream-to-observable
stream-to-observable
relies on any-observable
, which will search for an available Observable implementation. You need to install one yourself:
$ npm install --save zen-observable
or
$ npm install --save rxjs
If your code relies on a specific Observable implementation, you should likely specify one using any-observable
s registration shortcuts.
```const fs = require('fs'); const split = require('split'); const streamToObservable = require('stream-to-observable'); const readStream = fs .createReadStream('./hello-world.txt', {encoding: 'utf8'}) .pipe(split()); streamToObservable(readStream) .filter(chunk => /hello/i.test(chunk)) .map(chunk => chunk.toUpperCase()) .forEach(chunk => { console.log(chunk); // only the lines containing "hello" - and they will be capitalized });
The split
module above will chunk the stream into individual lines. This is often very handy for text streams, as each observable event is guaranteed to be a line.
Type: ReadableStream
Note: stream
can technically be any EventEmitter
instance. By default, this module listens to the standard Stream events (data
, error
, and end
), but those are configurable via the options
parameter. If you are using this with a standard Stream, you likely won't need the options
parameter.
await
Type: Promise
If provided, the Observable will not "complete" until await
is resolved. If await
is rejected, the Observable will immediately emit an error
event and disconnect from the stream. This is mostly useful when attaching to the stdin
or stdout
streams of a child_process
. Those streams usually do not emit error
events, even if the underlying process exits with an error. This provides a means to reject the Observable if the child process exits with an unexpected error code.
endEvent
Type: String
or false
Default: "end"
If you are using an EventEmitter
or non-standard Stream, you can change which event signals that the Observable should be completed.
Setting this to false
will avoid listening for any end events.
Setting this to false
and providing an await
Promise will cause the Observable to resolve immediately with the await
Promise (the Observable will remove all it's data
event listeners from the stream once the Promise is resolved).
errorEvent
Type: String
or false
Default: "error"
If you are using an EventEmitter
or non-standard Stream, you can change which event signals that the Observable should be closed with an error.
Setting this to false
will avoid listening for any error events.
dataEvent
Type: String
Default: "data"
If you are using an EventEmitter
or non-standard Stream, you can change which event causes data to be emitted to the Observable.
rxjs
observables - Observables implementationzen-observables
- Observables implementationdata
events on the stream will be emitted as events in the Observable. Since most native streams emit chunks
of binary data, you will likely want to use a TransformStream
to convert those chunks of binary data into an object stream. split
is just one popular TransformStream that splits streams into individual lines of text.
It's important to note that using this module disables back-pressure controls on the stream. As such, it should not be used where back-pressure throttling is required (i.e. high volume web servers). It still has value for larger projects, as it can make unit testing streams much cleaner.
Author: jamestalmage
Source Code: https://github.com/jamestalmage/stream-to-observable
License: MIT license
1608058980
ECMAScript is the specification upon which JavaScript is based. And since 2015, it has been evolving year after year, with the addition of features like classes, modules, async/await and many others. And what makes things even better is that today’s browsers add support for new features quickly, with a short time between releases. In this article, you’ll find out what is new in ECMAScript 2020. Have a good read!
#javascript #ecmascript #ecmascript-2020