Angular2 Observable with interval - javascript

I have a function that needs to be called about every 500ms. The way I am looking at doing it with angular2 is using intervals and observables. I have tried this function to create the observable:
counter() {
return Observable.create(observer => {
setInterval(() => {
return this.media.getCurrentPosition();
}, 500)
})
}
With this code for the subscriber:
test() {
this.playerService.initUrl(xxxx) // This works
this.playerService.counter().subscribe(data => {
res => {
console.log(data);
}
})
}
I am very new to observables and angular2 so I might be taking the wrong approach completely. Any help is appreciated.

The Observable class has a static interval method taking milliseconds (like the setInterval method) as a parameter:
counter() {
return Observable
.interval(500)
.flatMap(() => {
return this.media.getCurrentPosition();
});
}
And in your component or wherever:
test() {
this.playerService.initUrl(xxxx) // This works
this.playerService.counter().subscribe(
data => {
console.log(data);
}
);
}

Related

How figure out calling function setTimeout function at react

i have a react functional component.
Here is i have getData function, with this function i'm getting some data from api and then if data have i wan't to call anotherFunc();, But i wan't to do that after 3 second. I tried to put there setTimeout function but it's worked directly not wait 3 second. What i need to do?
function Hello(props) {
anotherFunc = () => {
console.log('hello');
}
const getData = () => {
let data = {
id: 1
}
axios.post(baseUrl, data).then(res => {
if (res.data) {
setTimeout(() => {
anotherFunc();
}, 3000);
}
});
}
return <h1>Something</h1>;
}
export default Hello;

Recursive observable method with delay

I am trying to create recursive server connection method with delay in Angular 8.
I tried this:
public connectToServerSafely(): Observable<boolean> {
if (this.isConnecting) {
return this.connectToServerSafely().pipe(delay(5000));
} else if (this.isConnected) {
return of(true);
} else {
return this.connectToServer();
}
}
Where connectToServer method returns Observable< boolean> depends on connection succeed or failed.
The problem is this delay method, I do not know why but I am facing with almost 2000 calls of connectToServerSafely() method until connection established. Connection is established after 1 second.
Why delay method does not really postopone recursive call of connectToServerSafely method (something as setTimeout method does)?
this.connectToServerSafely().pipe(delay(5000)) will not stop the function from calling itself. The delay operator will just delay the emitted values.
Here's my approach:
let isConnecting = true;
let isConnected = false;
timer(2000)
.subscribe(() => (isConnecting = false, isConnected = true));
function connSafely ()/* : Observable<any> */ {
console.warn('calling `connSafely`');
if (isConnecting) {
return timer(500).pipe(concatMap(() => connSafely()))
}
if (isConnected) {
return of(true);
}
return connectToServer();
}
function connectToServer () {
isConnecting = true;
return of('connecting');
}
connSafely().subscribe();
console.warn("calling 'connSafely'") should be called 5 times(1 for initial function call one 4 because 2000 / 500 = 4).
Note: It is important that you use one of the higher-order mapping operators(switchMap, concatMap, mergeMap/flatMap, exhaustMap) in order to make sure that all the subsequent function calls are automatically subscribed to/unsubscribed from.
Try to use tap(() => connSafely()) and you should only see message twice in the console.
StackBlitz. (scroll down until you find your example)
so looks like you set this.isConnecting and this.isConnected some where at the subscription to stream. If so code run async and you exit condition does not work because you design it on sync way
public connectToServerSafely(): Observable<boolean> {
if (this.isConnecting) {
// here function will be called until this.isConnecting change to false
return this.connectToServerSafely().pipe(delay(5000));
} else if (this.isConnected) {
return of(true);
} else {
return this.connectToServer();
}
}
This solution works for me:
public connectToServerSafely(): Observable<boolean> {
if (this.isConnecting) {
return new Observable((observer) => {
setTimeout(() => {
this.connectToServerSafely().subscribe(result => {
observer.next(result);
observer.complete();
});
}, 500);
});
} else if (this.isConnected) {
return of(true);
} else {
return this.connectToServer();
}
}

Inconsitant mergeMap behaviour

I am currently working on a file uploading method which requires me to limit the number of concurrent requests coming through.
I've begun by writing a prototype to how it should be handled
const items = Array.from({ length: 50 }).map((_, n) => n);
from(items)
.pipe(
mergeMap(n => {
return of(n).pipe(delay(2000));
}, 5)
)
.subscribe(n => {
console.log(n);
});
And it did work, however as soon as I swapped out the of with the actual call. It only processes one chunk, so let's say 5 out of 20 files
from(files)
.pipe(mergeMap(handleFile, 5))
.subscribe(console.log);
The handleFile function returns a call to my custom ajax implementation
import { Observable, Subscriber } from 'rxjs';
import axios from 'axios';
const { CancelToken } = axios;
class AjaxSubscriber extends Subscriber {
constructor(destination, settings) {
super(destination);
this.send(settings);
}
send(settings) {
const cancelToken = new CancelToken(cancel => {
// An executor function receives a cancel function as a parameter
this.cancel = cancel;
});
axios(Object.assign({ cancelToken }, settings))
.then(resp => this.next([null, resp.data]))
.catch(e => this.next([e, null]));
}
next(config) {
this.done = true;
const { destination } = this;
destination.next(config);
}
unsubscribe() {
if (this.cancel) {
this.cancel();
}
super.unsubscribe();
}
}
export class AjaxObservable extends Observable {
static create(settings) {
return new AjaxObservable(settings);
}
constructor(settings) {
super();
this.settings = settings;
}
_subscribe(subscriber) {
return new AjaxSubscriber(subscriber, this.settings);
}
}
So it looks something like this like
function handleFile() {
return AjaxObservable.create({
url: "https://jsonplaceholder.typicode.com/todos/1"
});
}
CodeSandbox
If I remove the concurrency parameter from the merge map function everything works fine, but it uploads all files all at once. Is there any way to fix this?
Turns out the problem was me not calling complete() method inside AjaxSubscriber, so I modified the code to:
pass(response) {
this.next(response);
this.complete();
}
And from axios call:
axios(Object.assign({ cancelToken }, settings))
.then(resp => this.pass([null, resp.data]))
.catch(e => this.pass([e, null]));

How to resolve a promise multiple times?

It might sound weird, but I'm looking for a way to resolve a promise multiple times. Are there any approaches to make this possible?
Think of the following example:
getPromise() {
const event = new Event('myEvent');
setTimeout(() => {
window.dispatchEvent(event);
}, 5000);
setTimeout(() => {
window.dispatchEvent(event);
}, 7000);
return new Promise((resolve) => {
window.addEventListener('myEvent', () => {
resolve('some value'));
});
resolve('some value'));
});
};
And then .then():
getPromise().then(data => {console.log(data)})
Should give the following result:
some value // initial
some value // after 5000ms
some value // after 7000ms
So I know there are libraries to stream data, but I'm really looking for a native non-callbak approach to achieve this.
How to resolve a promise multiple times?
You can't. Promises can only be resolved once. Once they have been resolved, they never ever change their state again. They are essentially one-way state machines with three possible states pending, fulfilled and rejected. Once they've gone from pending to fulfilled or from pending to rejected, they cannot be changed.
So, you pretty much cannot and should not be using promises for something that you want to occur multiple times. Event listeners or observers are a much better match than promises for something like that. Your promise will only ever notify you about the first event it receives.
I don't know why you're trying to avoid callbacks in this case. Promises use callbacks too in their .then() handlers. You will need a callback somewhere to make your solution work. Can you explain why you don't just use window.addEventListener('myEvent', someCallback) directly since that will do what you want?
You could return a promise-like interface (that does not follow Promise standards) that does call its notification callbacks more than once. To avoid confusion with promises, I would not use .then() as the method name:
function getNotifier() {
const event = new Event('myEvent');
setTimeout(() => {
window.dispatchEvent(event);
}, 500);
setTimeout(() => {
window.dispatchEvent(event);
}, 700);
let callbackList = [];
const notifier = {
notify: function(fn) {
callbackList.push(fn);
}
};
window.addEventListener('myEvent', (data) => {
// call all registered callbacks
for (let cb of callbackList) {
cb(data);
}
});
return notifier;
};
// Usage:
getNotifier().notify(data => {console.log(data.type)})
I have a solution in Typescript.
export class PromiseParty {
private promise: Promise<string>;
private resolver: (value?: string | PromiseLike<string>) => void;
public getPromise(): Promise<string> {
if (!this.promise) {
this.promise = new Promise((newResolver) => { this.resolver = newResolver; });
}
return this.promise;
}
public setPromise(value: string) {
if(this.resolver) {
this.resolver(value);
this.promise = null;
this.resolver = null;
}
}
}
export class UseThePromise {
public constructor(
private promiseParty: PromiseParty
){
this.init();
}
private async init(){
const subscribe = () => {
const result = await this.promiseParty.getPromise();
console.log(result);
subscribe(); //resubscribe!!
}
subscribe(); //To start the subscribe the first time
}
}
export class FeedThePromise {
public constructor(
private promiseParty: PromiseParty
){
setTimeout(() => {
this.promiseParty.setPromise("Hello");
}, 1000);
setTimeout(() => {
this.promiseParty.setPromise("Hello again!");
}, 2000);
setTimeout(() => {
this.promiseParty.setPromise("Hello again and again!");
}, 3000);
}
}

Fire callback after two separate successful http requests

Root component of my application on init call two asynchronous functions from my services to get data. I would like to know how to call a function after they are both completed. I am using angular 2.0.0-alpha.44 and typescript 1.7.3
import {Component, OnInit} from 'angular2/angular2';
import {ServiceA} from './services/A';
import {ServiceB} from './services/B';
#Component({
selector: 'app',
template: `<h1>Hello</h1>`
})
export class App {
constructor(
public serviceA: ServiceA,
public serviceB: ServiceB
) { }
onInit() {
// How to run a callback, after
// both getDataA and getDataB are completed?
// I am looing for something similar to jQuery $.when()
this.serviceA.getDataA();
this.serviceB.getDataB();
}
}
serviceA.getDataA and serviceA.getDataB are simple http get functions:
// Part of serviceA
getDataA() {
this.http.get('./some/data.json')
.map(res => res.json())
.subscribe(
data => {
// save res to variable
this.data = data;
},
error => console.log(error),
// The callback here will run after only one
// function is completed. Not what I am looking for.
() => console.log('Completed')
);
}
A simple still parallel solution would be something like:
let serviceStatus = { aDone: false, bDone: false };
let getDataA = (callback: () => void) => {
// do whatver..
callback();
}
let getDataB = (callback: () => void) => {
// do whatver..
callback();
}
let bothDone = () => { console.log("A and B are done!");
let checkServiceStatus = () => {
if ((serviceStatus.aDone && serviceStatus.bDone) == true)
bothDone();
}
getDataA(() => {
serviceStatus.aDone = true;
checkServiceStatus();
});
getDataA(() => {
serviceStatus.bDone = true;
checkServiceStatus();
});
I personally use RxJS to get me out of sticky situations like this, might be worth looking at.
EDIT:
Given feedback that RxJS is actually being used:
let observable1: Rx.Observable<something>;
let observable2: Rx.Observable<something>;
let combinedObservable = Rx.Observable
.zip(
observable1.take(1),
observable2.take(1),
(result1, result2) => {
// you can return whatever you want here
return { result1, result2 };
});
combinedObservable
.subscribe(combinedResult => {
// here both observable1 and observable2 will be done.
});
This example will run both observables in parallel and combine the result into one result when they are both done.
You could pass getDataA and getDataB callbacks in their function definitions, then call whatever you want in order:
function getDataA(callback) {
// do some stuff
callback && callback();
}
function getDataB(callback) {
// do some stuff
callback && callback();
}
function toCallAfterBoth() {
// do some stuff
}
getDataA(getDataB(toCallAfterBoth));
You could nest your function calls.
EG:
function getDataA (callback) {
var dataA = {test:"Hello Data A"};
callback && callback(dataA);
}
function getDataB (callback) {
var dataB = {test:"Hello Data B"};
callback && callback(dataB);
}
getDataA(function (dataA) {
getDataB(function (dataB) {
console.log("Both functions are complete and you have data:");
console.log(dataA);
console.log(dataB);
});
});

Categories