mostjs-community / subject Goto Github PK
View Code? Open in Web Editor NEWSubjects for Most.js
License: MIT License
Subjects for Most.js
License: MIT License
Was using previous version, and switched to new version, got the following trace :
ERROR in [default] C:\Users\toshiba\WebstormProjects\sparks-frontend\node_modules\most-subject\lib\es2015\combinators\er
ror.d.ts:1:0
Cannot find type definition file for 'node'.
ERROR in [default] C:\Users\toshiba\WebstormProjects\sparks-frontend\node_modules\most-subject\lib\es2015\interfaces.d.t
s:1:0
Cannot find type definition file for 'node'.
ERROR in [default] C:\Users\toshiba\WebstormProjects\sparks-frontend\node_modules\most-subject\lib\es2015\subjects\async
\index.d.ts:1:0
Cannot find type definition file for 'node'.
ERROR in [default] C:\Users\toshiba\WebstormProjects\sparks-frontend\node_modules\most-subject\lib\es2015\subjects\sync\
index.d.ts:1:0
Cannot find type definition file for 'node'.
ERROR in [default] C:\Users\toshiba\WebstormProjects\sparks-frontend\src\pages\ResetPassword\ResetPasswordComponent.test
.ts:19:8
Module '"C:/Users/toshiba/WebstormProjects/sparks-frontend/node_modules/most-subject/lib/es2015/index"' has no exported
member 'holdSubject'.
ERROR in [default] C:\Users\toshiba\WebstormProjects\sparks-frontend\src\utils\testing\runTestScenario.test.ts:6:8
Module '"C:/Users/toshiba/WebstormProjects/sparks-frontend/node_modules/most-subject/lib/es2015/index"' has no exported
member 'holdSubject'.
That seems to have to do with the first line
/// <reference types="node" />
Add stream.drain()
to the various implementations
Coming from RxJS Subjects are considered 'hot' by default.
with "most-subject": "^4.1.3",
calling next
on a holdSubject
before an observer is attached produces an error because this.scheduler
is pointing to a an improperly loaded module.
fixed by replacing (in SubjectSource.ts):
const defaultScheduler = require('most/lib/scheduler/defaultScheduler');
with:
const defaultScheduler = require('most/lib/scheduler/defaultScheduler').default;
At first I tried import defaultScheduler from 'most/lib/scheduler/defaultScheduler';
but it complained it couldn't find the module...?
The reason this error doesn't happen with a non-holding stream is due to the next
method only making the scheduler call after an observer is attached which replaces the broken scheduler with the one from higher up the call stack, while the holding subject calls the scheduler straight away to buffer itself:
HoldSubjectSource.ts:
next (value: T) {
if (this.scheduler === void 0) { return; }
const time = this.scheduler.now();
this.buffer = dropAndAppend({time, value}, this.buffer, this.bufferSize);
if (this.active) {
this._next(time, value);
}
}
SubjectSource.ts:
next (value: T): void {
if (!this.active || this.scheduler === void 0) return;
this._next(this.scheduler.now(), value);
}
run (sink: Sink<T>, scheduler: Scheduler): Disposable<T> {
const n = this.add(sink);
if (n === 1) {
this.scheduler = scheduler;
this.active = true;
}
return new SubjectDisposable<T>(this, sink);
}
I feel like https://github.com/mostjs-community/most-subject/blob/master/src/HoldSubjectSource.ts#L30 should be moved above the if(!this.isActive...)
line. Currently the @cycle/storage
driver emits item streams using a startWith
. That item is currently pushed into a basic most Subject using adapt
during the initial wiring of the stream, which means the values that are sent are being dropped since there are no active listeners.
I hacked the most-adapter
code to start using a holdSubject
to see if that fixed things but it doesn't because holdSubject
doesn't buffer the value that is sent into it unless it has listeners. I think that's wrong. I think a hold subject should buffer values sent in even when there are no listeners. The purpose of a holdSubject is "value over time" so shouldn't it maintain the values it receives so the first listener gets a value immediately without having to wait for a follow-on emission?
when calling next
from scan
weird stuff is happening.
here is simple example reproducing this issue:
var mostSubject = require('most-subject');
var subject = new mostSubject.holdSubject(10);
var acc = subject.stream.scan(function(acc, i) {
console.log('// '+acc+', '+i);
var result = acc + i;
if (i == 3) {
subject.observer.next(4);
}
console.log('\\\\ '+result);
return result;
}, 0);
var subscription = acc.observe( (x) => { console.log('Next: ' + x) });
subject.observer.next(1);
subject.observer.next(2);
subject.observer.next(3);
setTimeout(subject.observer.complete, 0);
here is the log.
Next: 0
// 0, 1
\\ 1
Next: 1
// 1, 2
\\ 3
Next: 3
// 3, 3
// 3, 4
\\ 7
Next: 7
\\ 6
Next: 6
// 6, 4
\\ 10
Next: 10
if complete
is not called using setTimeout
- setTimeout(subject.observer.complete, 0);
+ subject.observer.complete();
then this is what log looks like:
Next: 0
// 0, 1
\\ 1
Next: 1
// 1, 2
\\ 3
Next: 3
// 3, 3
\\ 6
Next: 6
but same code using Rx.ReplaySubject works ok.
var Rx = require('rx');
var subject = new Rx.ReplaySubject(10);
var acc = subject.scan(function(acc, i) {
console.log('// '+acc+', '+i);
var result = acc + i;
if (i == 3) {
subject.onNext(4);
}
console.log('\\\\ '+result);
return result;
}, 0);
var subscription = acc.subscribe(
(x) => { console.log('Next: ' + x); },
(err) => { console.log('Error: ' + err); },
() => { console.log('Completed'); }
);
subject.onNext(1);
subject.onNext(2);
subject.onNext(3);
subject.onCompleted();
here is the log:
// 0, 1
\\ 1
Next: 1
// 1, 2
\\ 3
Next: 3
// 3, 3
\\ 6
Next: 6
// 6, 4
\\ 10
Next: 10
Completed
Add a hold stream for conveniece
This is a very common used process
import hold from '@most/hold'
function holdSubject() {
const {sink, stream} = subject()
const holdStream = hold(stream)
return {sink, stream: holdStream}
}
While testing out (hacking) fixes for #22 I happened to create a most.combine(f, ...sources).take(1)
. The sources were three of the above referenced holdSubjects
, modified to buffer emissions even without listeners. Upon successfully getting the first emission in my hacked set-up, my test code crashed with a message similar to this:
index.js:5 TypeError: Cannot read property 'dispose' of undefined
at SliceSink.dispose (slice.js:102)
at SliceSink.event (slice.js:96)
at CombineSink.event (combine.js:97)
at IndexSink.event (IndexSink.js:21)
at Object.pushEvents (util.js:23)
at HoldSubjectSource.add (HoldSubjectSource.js:19)
at HoldSubjectSource.BasicSubjectSource.run (SubjectSource.js:24)
at Combine.run (combine.js:66)
at new SliceSink (slice.js:77)
at Slice.run (slice.js:70)
and while investigating why I saw that BasicSubjectSource adds listeners synchronously, which seems wrong.
The line which crashes is in the SliceSink constructor (line 77):
this.disposable = dispose.once(source.run(this, scheduler));
This line triggers run calls up the observable chain. When the sources for the combine are called they emit their buffered values into the CombineListener immediately upon seeing a run call and immediately (synchronously) upon the required number of streams emitting a value, combine
emits to the take
operator which in this case only accepts one value and immediately completes the stream and immediately tries to call this.disposable.dispose
but in the corner case of take(1)
, this.disposable
has yet to be set, hence the crash. By deferring the .add
calls using a setTimeout(...)
in BasicSubjectSource.prototype.run
I was able to bypass this crash by adding listeners asynchronously, ensuring that this.disposable
is set before any emissions take place. My approach is quite hacky and uses setTimeout
(https://github.com/ntilwalli/most-subject/blob/master/src/SubjectSource.ts#L19), it looks like:
export class BasicSubjectSource<T> implements SubjectSource<T> {
protected scheduler: Scheduler = defaultScheduler;
protected sinks: Sink<T>[] = [];
protected active: boolean = false;
run (sink: Sink<T>, scheduler: Scheduler): Disposable<T> {
const that = this;
const thatScheduler = scheduler;
const thatSink = sink;
setTimeout(() => {
const n = that.add(thatSink);
if (n === 1) {
that.scheduler = thatScheduler;
that.active = true;
}
}, 4);
return new SubjectDisposable<T>(this, sink);
}...
I would assume the proper solution would involve using the scheduler in some way (maybe a scheduler.asap
call of some sort?)
BTW, my solution fixes my issue but using the setTimeout
causes a bunch of the most-subject
tests to fail, mostly with timeouts...
In most-subject
4.1.3 our codebase was making use of the following pattern to create an imperative stream which we could push new events to:
import { subject } from 'most-subject';
const $authToken = subject();
$authToken.next("hello!");
This factory function has been removed from the 5.x API with no mention made to it in the CHANGELOG; looking at the code in the 4.1.1 tag it would appear that the migration should be:
import { asAsync, BasicSubjectSource } from 'most-subject';
const $authToken = asAsync(new BasicSubjectSource())
However as of 5.2 BasicSubjectSource
appears to have been removed from the exported API - was this intentional? If so is there a migration path for the above code?
Thanks!
In your docs there is a mention of circular dependencies.
I think I am not sure what you mean by it.
Is this an example of circular dependency
{subject} = require 'most-subject'
stream = subject!
stream.map (vals) ->
stream.next vals
.drain!
stream.next 1
NPM has not been updated with the latest version posted on github. Can this be published?
Coming from RxJS in need of performance, the subject feature seems like the most powerful observable factory primitive to actually do whatever we want. I found this and doc is broken ๐ข .
Please fix it ? ๐
I have the Bower most.js file referenced in index.html script tags. The file supports my monad.js file, which is referenced in script tags below it. This setup facilitates experimentation in the browser console. I import the npm most package, along with the motorcycle package, in my main application file.
Now I want to define some things in monad.js that depend on most-subject. I need to put something in script tags under most.js and above monad.js. Any suggestions? Any chance something along the lines of the most.js file will become available on Bower?
Hello,
I'm trying to use the @most/core
together with the most-subject
to implement a state reducer loop and epic similar to the redux-most
.
I've got the basic concept working, but the stream never ends when there is a cyclic dependency even when the initial stream closes.
import { attach, create } from 'most-subject'
import { filter, map, merge, now } from '@most/core'
import { Time } from '@most/types'
import { newDefaultScheduler } from '@most/scheduler'
const input = now(5)
const [ sink, stream ] = create<number>()
const combined = merge(input, stream)
const feedback = map(a => a * 2, filter(a => a % 2 === 1, combined))
attach(sink, feedback)
combined.run({
end(): void {
console.log('loop ended')
},
error(time, err: Error): void {
console.log('error', err)
},
event(time, value): void {
console.log('event', value)
}
}, newDefaultScheduler())
The output is:
event 5
event 10
The expected output:
event 5
event 10
loop ended
Do you have any idea what is wrong? I'm not sure if this is even possible, but it would be great!
Update @most/hold to 1.0.0
For compatibility with most 0.17.1
๐
I would have done so myself, but TS is unfamiliar to me.
Create a subject which behaves similarly to RxJS' BehaviorSubject
Easier transitioning from RxJS to Most
I used most-subject successfully in the past. Then I switched to xstream for a while. Now I am trying to use most-subject version 4.02 but it won't load when I try it in Chrome. I am bundling with Webpack. I moved the whole npm package into bower_components because I need to get node_modules out of the way when I compile the server. I started out with just the /dist/most-subject.js file in bower_components and get identical results to the ones shown here. This is a screen shot of the top of of the Chrome console log:
Here is line 9876 of the of the Webpack bundle:
And here is line 9832
The most relevant line seems to be line 7434. Here it is:
This is a screen shot of my index.html file:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.