is there any way to return a promise every 1 minute continuously?
i was trying something like this but it returns promise only once at the beginning:
startWork() {
this.dataService.startPing(details).then((result) => {
this.timeSlotsRefresh();
}, (err) => {
console.log(err);
});
}
and then:
startPing() {
let startingTime = new Date();
return new Promise((resolve, reject) => {
let source = Rx.Observable.timer(startingTime, 60000).timeInterval().pluck('interval');
this.Subscription = source
.subscribe(data => {
this.http.post('http://localhost:63203/api/Ping', JSON.stringify(this.offlinePings[i]))
.map(res => res.json())
.subscribe(data => {
resolve(data);
}, (err) => {
reject(err);
});
});
});
}
it has to basically inform this function every 1 minute to call this.timeSlotsRefresh(); to refresh the data, how can i achieve that?
#Injectable
class Ping {
readonly observable = Rx.Observable.interval(60000);
subscribe(...cbs) {
return this.observable.subscribe(...cbs);
}
}
#Component
class Foo implements OnInit, onDestroy {
private subscription = null;
constructor(private ping: Ping) {}
onPing(count) {}
onPingError(error) {}
onPingFinish() {}
ngOnInit() {
this.subscription = this.ping.subscribe(
(...d) => this.onPing(...d),
(...e) => this.onPingError(...e),
(...f) => this.onPingFinish(...f)
);
}
ngOnDestroy() {
this.subscription.unsubscribe()
}
}
Promises are meant to work only once, you may need for something similar to a streaming and Observables could suit better.
using rx with the interval operator:
var source = Rx
.Observable
.interval(2000 /* ms */)
.map(id => fetch(`https:\/\/jsonplaceholder.typicode.com\/posts\/${id}`).then(res => res.json()))
;
var subscription = source
.subscribe(post => console.log('New Post', post))
;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.0/Rx.js"></script>
Related
I have a API which called the bank end :
this.http.get(`http://localhost:44301/consentinitiation/${this.qid}`)
.pipe(retryWhen(_ => {
this.showIt=true
return interval(1000)
}))
.subscribe(result => {result
console.log(result);
this.qrcodelink=result["qrCodeLink"];
setTimeout(() => {
this.loadingSpinner=false;
}, 5000);
})
It has a result and has a status which is "Recieved" after that i should call the API again unstil i get the status "Finalized" and dont how to call the API again ,after the first call is finished,because if i write it below the first one i guess they will call the simultaneously,any idea?
the problem that u describe in description is called polling ( make request in interval until u got an expected result )
here is poll implementation in rxjs way
makeSomeRequestsToBank() {
this.http.get('https://').pipe(
switchMap(result => {
// if status is recieved, start polling
if (result.status === 'Recieved') {
return this.pollStatus();
}
if (result.status === 'Finalized') {
return of(result)
}
// else do some thing else, depends on u business logic
// keep in mind that switchMap should return an observable for futher chaining
return of(undefined);
}),
).subscribe(result => {
if (!result) return;
this.qrcodelink=result["qrCodeLink"];
setTimeout(() => {
this.loadingSpinner=false;
}, 5000);
}
pollStatus(): Observable<any> {
const POLLING_INTERVAL = 700; // poll in ms
const isSuccessFn = (response: string) => response === 'Finalized'; // the condition to stop polling and return result
return timer(0, POLLING_INTERVAL).pipe(
switchMap(() => this.http.get('https://')),
skipWhile(response => isSuccessFn(response)),
);
}
You can do it with using Promise.
ngOnInit(){
this.callFirstApi();
}
firstApi(): Promise<any> {
return new Promise((resolve, reject) => {
this.http.get(API_URL).subscribe((data) => {
resolve(data);
}, (error) => {
reject(error);
});
});
}
secApi(): Promise<any> {
return new Promise((resolve, reject) => {
this.http.get(API_URL).subscribe((data) => {
resolve(data);
}, (error) => {
reject(error);
});
});
}
callFirstApi(){
this.firstApi().then(response => {
this.callSecApi();
}).catch(err => {
})
}
callSecApi(){
this.secApi().then(response => {
}).catch(err => {
})
}
I making an api call using Promise.all as below:
Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
return new Promise((resolve, reject) => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
this.serviceB.retry(oretry).subscribe(resolve);
});
});
}))
.then(() => {
this.dialog.close();
})
.catch(err => {
console.log(err);
});
The above code is working fine.
Now I want to make another api call after the successful completion of this.serviceB.retry(oretry).
The second api is this.serviceB.createDbEntry(sentry) and sentry looks as below:
const sretry: SDInterface = {
hostName,
Id: this.Id.slice(0, this.Id.length),
reason: this.reason
};
And, I am doing it as below
Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
return new Promise((resolve, reject) => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
const sretry: SDInterface = {
hostName,
Id: this.Id.slice(0, this.Id.length),
reason: this.reason
};
this.serviceB.retry(oretry).subscribe(resolve);
this.serviceB.createDbEntry(sentry).subscribe(resolve);
});
});
}))
.then(() => {
this.dialog.close();
})
.catch(err => {
console.log(err);
});
The above code is giving an error:
error: "SequelizeValidationError: string violation: Id cannot be an array or an object"
It is looks like it is not calling the second api for every Id
You may want to take a look a forkJoin
import { Observable, forkJoin } from 'rxjs';
And then
ngOnInit() {
let one = this.http.get('some/api/1') //some observable;
let two = this.http.get('some/api/2') // another observable;
forkJoin([one, tow]).subscribe(response => {
// results[0] is our one call
// results[1] is our second call
let var1 = response[1];
let var2 = response[0];
}/*, error => { in case error handler } */);
}
Wouldn't it be better to use Promise.all() once more?
Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
return new Promise((resolve, reject) => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
this.serviceB.retry(oretry).subscribe(resolve);
});
})
.then(() => {
return Promise.all(this.Id.slice(0, this.Id.length).map(id => {
return new Promise((resolve, reject) => {
const sretry: SDInterface = {
hostName,
Id: id,
reason: this.reason
};
this.serviceB.createDbEntry(sentry).subscribe(resolve);
});
})
});
}))
.then(() => {
this.dialog.close();
})
.catch(err => {
console.log(err);
});
And using toPromise() will make the code more concise.
Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
return this.serviceB.retry(oretry).toPromise();
})
.then(() => {
return Promise.all(this.Id.slice(0, this.Id.length).map(id => {
const sretry: SDInterface = {
hostName,
Id: id,
reason: this.reason
};
this.serviceB.createDbEntry(sentry).toPromise();
})
});
}))
.then(() => {
this.dialog.close();
})
.catch(err => {
console.log(err);
});
Use combineLatest, in Angular we use RxJs not promises.
combineLatest(
[this.http.get('call1'), this.http.get('call2')]
).subscribe(([result1, result2]) => {
// do stuff with result1 and result2
});
promise.all takes input in an array and gives response in an array,
Create 2 functions each with your asynchronous logic returning a promise,
Say funcA and funcB, then use below to invoke them parellely
Promise.all([funcA(this.hostName), funcB(this.id)])
.then(respones => {
console.log(responses[0]); //return value for funcA
console.log(responses[1]); //return value for funcB
})
.catch(err => console.log(err));
I am assuming your logic of functions are correct, I just copy-pasted from your question and gave them structure
const funcA = (hostName) => {
hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
return new Promise((resolve, reject) => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
this.serviceB.retry(oretry).subscribe(resolve);
});
});
});
}
const funcB = (Id) => {
Id.slice(0, this.Id.length).map(id => {
return new Promise((resolve, reject) => {
const sretry: SDInterface = {
hostName,
Id: id,
reason: this.reason
};
this.serviceB.createDbEntry(sentry).subscribe(resolve);
});
})
}
I've had a good look around to try and solve this but can't find an answer that works.
I'm trying to implement a callback for an additional function when a subscribe() method successfully returns an 'contacts$' observable, but using complete() on the subscription does not do anything.
I've also tried using finally() on the observable as suggested elsewhere, but this also doesn't work.
Using complete():
ngOnInit() {
this.getContacts().subscribe(
data => {
this.contacts = data;
console.log('NewInvoice.contacts:', data);
this.selectedContactId = this.contacts[0].id;
console.log('selectedContactId: ' + this.selectedContactId);
},
error => {
console.error('Error getting contacts via subscribe() method:', error);
},
() => {
this.getSelectedContact();
}
)
}
Using finally():
ngOnInit() {
this.getContacts()
.finally(() => console.log('a'))
.subscribe(
data => {
this.contacts = data;
console.log('NewInvoice.contacts:', data);
this.selectedContactId = this.contacts[0].id;
console.log('selectedContactId: ' + this.selectedContactId);
},
error => {
console.error('Error getting contacts via subscribe() method:', error);
},
() => {
this.getSelectedContact();
}
)
}
Method for callback on observable completion:
getSelectedContact() {
this.contactsCollection.doc(this.selectedContactId).ref.get().then(snapshot => {
this.selectedContact = snapshot.data() as Contact;
console.log('selectedContact:', this.selectedContact);
})
}
Difficult to say without more info, but I'll give a shot:
ngOnInit() {
this.getContacts()
.subscribe(
data => {
this.contacts = data;
console.log('NewInvoice.contacts:', data);
this.selectedContactId = this.contacts[0].id;
console.log('selectedContactId: ' + this.selectedContactId);
},
error => {
console.error('Error getting contacts via subscribe() method:', error);
},
() => {
this.getSelectedContact()
.asObservable()
.subscribe((a) => console.log(a));
}
)
}
And :
getSelectedContact() {
return this.contactsCollection.doc(this.selectedContactId).ref.get().then(snapshot => {
this.selectedContact = snapshot.data() as Contact;
console.log('selectedContact:', this.selectedContact);
})
}
Or a little cleaner :
const callback = (a) => console.log(a);
...
() => {
this.getSelectedContact(callback);
}
...
getSelectedContact(callback) {
this.contactsCollection.doc(this.selectedContactId).ref.get()
.then(snapshot => {
this.selectedContact = snapshot.data() as Contact;
console.log('selectedContact:', this.selectedContact);
})
.then(a => callback(a));
}
Lastly as #Picci suggested :
this.getContacts()
.last()
.exhaustMap((data) => this.getSelectedContact(data))
.map(a => console.log(a))
.subscribe();
Beware that all the above code is absoultely not tested and only for reference.
(Obviously this doesn't have much to do with typescript, except that the example code is in ts).
import { createWriteStream, WriteStream } from "fs";
export class Util {
public static openWrite(path: string): Promise<WriteStream> {
return new Promise<WriteStream>((resolve, reject) => {
const result = createWriteStream(path);
const onError = (err: Error) => {
// How to remove both listeners here?
reject(err);
}
const onOpen = (fd: number) => {
// How to remove both listeners here?
resolve(result);
};
result.on("error", onError);
result.on("open", onOpen);
});
}
}
The code should say it all. I have a hard time to see how the function should be written such that it handles both the success and failure scenarios correctly, while ensuring that all added event handlers are removed when everything is done.
Of course, there is always the possibility to call removeAllListeners, but that looks like a hack to me.
I think this is a good use-case for finally.
let onError, onOpen;
const result = createWriteStream(path);
return new Promise<WriteStream>((resolve, reject) => {
onError = (err: Error) => {
// How to remove both listeners here?
reject(err);
}
onOpen = (fd: number) => {
// How to remove both listeners here?
resolve(result);
};
result.on("error", onError);
result.on("open", onOpen);
}).finally(() => {
result.removeListener("error", onError);
result.removeListener("open", onOpen);
});
Or if you know that no other listeners are already attached to the EventEmitter you can simplify it as follows:
const result = createWriteStream(path);
return new Promise<WriteStream>((resolve, reject) => {
result.on("error", reject);
result.on("open", resolve);
}).then(() => {
return result;
}).finally(() => {
result.removeAllListeners("error");
result.removeAllListeners("open");
});
In NodeJS, all Stream is an EventEmitter (https://nodejs.org/api/stream.html#stream_stream)
The EventEmitter has a method called removeListener. So try to do the Following:
return new Promise<WriteStream>((resolve, reject) => {
const result = createWriteStream(path);
const onError = (err: Error) => {
result.removeAllListeners()
reject(err);
}
const onOpen = (fd: number) => {
result.removeAllListeners()
resolve(result);
}
result.on("error", onError);
result.on("open", onOpen);
});
Here's what I finally went with ...
public static async openWrite(path: string): Promise<WriteStream> {
const factory = new StreamFactory(() => createWriteStream(path));
try {
return await factory.get();
} finally {
factory.dispose();
}
}
... with StreamFactory defined as follows:
class StreamFactory<T extends EventEmitter> {
private stream: T;
private onOpen: (fd: number) => void;
private onError: (err: Error) => void;
private readonly promise: Promise<T>;
public constructor(create: () => T) {
this.promise = new Promise<T>((resolve, reject) => {
this.stream = create();
this.onOpen = fd => resolve(this.stream);
this.onError = err => reject(err);
this.stream.on("open", this.onOpen).on("error", this.onError);
});
}
public get(): Promise<T> { return this.promise; }
public dispose(): void {
this.stream.removeListener("open", this.onOpen).removeListener("error", this.onError);
}
}
I've tested the failure and success paths of the above and the event handlers are removed correctly in both cases. Of course, this is just a variation of Jakes answer, so +1 to him for pointing this out.
This has the advantage of not resorting to Promise.finally, which doesn't seem to be available on my platform (Node 8.x).
It appears that it is definitely not a good idea to use removeAllListeners(). At least on my platform, the library itself seems to add a listener for "open" when an error occurs. removeAllListeners() would remove that with possibly unintended consequences.
Can you tell me why this () success method is not firing? When I use forkjoin() it is working nicely.Success method must fire every time no? Hope it is like a final method on try-catch block.
Note: Please see the inline comments too.
.ts
getAllBooksReadAndUnRead(id: number, loader?) {
this.article.getAllBooksReadAndUnRead(id)
.map((res: any) => res.json())
.subscribe(res => {
this.setAllData(res); //it comes to here
this.loadingControllerService.dismissLoader(loader);//I have to put this here.Then no problem.But I think it is duplicate of work???
},
error => {this.loadingControllerService.dismissLoader(loader);},
() => {this.loadingControllerService.dismissLoader(loader);}//not fire
});
}
Api call
getAllBooksReadAndUnRead(bookId) {
return this.apiSer.get(`${config.fromThisBook}?page=all&book[]=${bookId}`);
}
Generic method:
get(api) {
return new Observable(observer => {
let header = new Headers();
this.createHeader(header)
.then(() => {
let options = new BaseRequestOptions();
options.withCredentials = true;
options.headers = header;
this.http.get(api, options)
.subscribe(response => {
observer.next(response);
}, (e) => {
observer.error(e);
});
})
})
}
post()
post(url, params): Observable<any> {
return new Observable(observer => {
let header = new Headers();
this.createHeader(header)
.then(() => {
let options = new RequestOptions({ headers: header });
this.http.post(url, params, options)
.subscribe(response => {
observer.next(response);
observer.complete();
}, (e) => {
observer.error(e);
});
})
})
}
The problem is that you never trigger complete in your custom producer. You need something like this:
get(api) {
return new Observable(observer => {
let header = new Headers();
this.createHeader(header)
.then(() => {
let options = new BaseRequestOptions();
options.withCredentials = true;
options.headers = header;
this.http.get(api, options).subscribe(
response => observer.next(response),
(e) => observer.error(e),
() => observer.complete(); <-------------------------
);
})
})
}
Also I think you don't need a custom producer, try like this:
get(api) {
return Observable.from(this.createHeader()).map((header) => {
let options = new BaseRequestOptions();
options.withCredentials = true;
options.headers = header;
return this.http.get(api, options);
}).mergeAll();
}
Here is how it works:
Observable.from(this.createHeader()) returns an observable that will deliver values once the promise is resolved
.map((header) => { observes the value that comes from returned promise and makes an HTTP request and returns the result in the form of the observable
mergeAll() - since the previous operation returns and observable, we need to flatten it
I try to avoid wrapping code blocks in parentheses unless I have to, as it makes it easier to confuse their placement. For example, you have an extra closing } in your second to last line that may be causing an issue:
getAllBooksReadAndUnRead(id: number, loader?) {
this.article.getAllBooksReadAndUnRead(id)
.map((res: any) => res.json())
.subscribe(res => {
this.setAllData(res);//it comes to here
},
error => {this.loadingControllerService.dismissLoader(loader);},
() => {this.loadingControllerService.dismissLoader(loader);}//not fire
);
}
I would be inclined to simplify the parentheses like this:
getAllBooksReadAndUnRead(id: number, loader?) {
this.article.getAllBooksReadAndUnRead(id)
.map(res: any => res.json())
.subscribe(res => {
this.setAllData(res);//it comes to here
},
error => this.loadingControllerService.dismissLoader(loader),
() => this.loadingControllerService.dismissLoader(loader)//not fire
)};