How to attach function to the Observer while using Observable in Angular? - javascript

I know how to emit a value to the observer and subscribe to them using observable, as shown here
var observable = new Observable(observer => {
observer.next(1);
observer.next(2);
observer.next(3);
}).subscribe((success) => {
console.log(success);
})
but if I want to do the same thing with the function, ie. I have something like this, then how can I achieve it
var observable = new Observable(observer => {
observer.next(function () {
setTimeout(() => {
1
}, 1000)
})
observer.next(function () {
setTimeout(() => {
2
}, 1000)
})
observer.next(function () {
setTimeout(() => {
3
}, 1000)
})
}).subscribe((success) => {
console.log(success);
})
is it possible, all I have to do is call a series of async functions, how can I do it
UPDATE
i want to call a series of asnc fuctions in a sequence, ie. the second should be called only after the completion of the first functions operation and so on and so forth

You can do something like this. This is just the fundamental here. You can call your async instead of emitting static values.
var ParentObservable = new Observable();
ParentObservable.subscribe((res) => {
//res is your response from async calls
//Call asyncCall again from here
})
function asyncCall(){
this.http.get("your URL").map((res)=> res.json()).subscribe((res)=>{
ParentObservable.next(res);
})
}

Related

How to avoid the creation of a new promise for each click?

I have a click that calls the method:
public clickEvent() {
this.createIframe().then((iframe) => { // Return iframe or create if is not before needed inside
// Async hard logic here
})
}
Problem is when user clicks a lot of times clickEvent() it fires promise and then fires a hard logic inside.
How to avoid click until logic inside is not finished?
Or disable to call logic inside if it is done?
If you're using Angular, I think you can convert the click event into an observable and then use the variety of operators such as exhaustMap to achieve this.
import { exhaustMap, fromEvent } from 'rxjs';
....
#ViewChild('btnId') btnElementRef!: ElementRef<HTMLButtonElement>;
ngAfterViewInit(): void {
fromEvent(this.btnElementRef.nativeElement, 'click')
.pipe(
exhaustMap(() => this.createIframe())
)
.subscribe((iframe) => {
// hard coded async logic here
});
}
);
This will ignore sub-sequent click until the Promise resolve first.
Further more, if you want to disable the button and display somekind of loading indicator, you can also add a variable to track that inside the stream using tap
fromEvent(this.btnElementRef.nativeElement, 'click')
.pipe(
tap(() => isProcessing = true),
exhaustMap(() => this.createIframe())
)
.subscribe((iframe) => {
isProcessing = false;
// hard coded async logic here
});
Make createIframe cache its Promise (like as an instance property), and return that first if it exists, instead of starting another. For example:
// example function that creates the Promise
const createPromise = () => {
console.log('creating Promise');
return new Promise(resolve => setTimeout(resolve, 3000));
}
class SomeClass {
createIframe() {
if (this.iframePromise) return this.iframePromise;
this.iframePromise = createPromise();
return this.iframePromise;
}
clickEvent() {
this.createIframe().then((iframe) => {
console.log('clickEvent has received the Promise and is now running more code');
})
}
}
const s = new SomeClass();
button.onclick = () => s.clickEvent();
<button id="button">click to call clickEvent</button>
If you also want to prevent // Async hard logic here from running multiple times after multiple clicks, assign something to the instance inside clickEvent instead.
// example function that creates the Promise
const createPromise = () => {
console.log('creating Promise');
return new Promise(resolve => setTimeout(resolve, 3000));
}
class SomeClass {
createIframe() {
return createPromise();
}
clickEvent() {
if (this.hasClicked) return;
this.hasClicked = true;
this.createIframe().then((iframe) => {
console.log('clickEvent has received the Promise and is now running more code');
})
}
}
const s = new SomeClass();
button.onclick = () => s.clickEvent();
<button id="button">click to call clickEvent</button>

Node.js and Jest: Testing promise loop, count how many times function has been called

I want to test my code using JEST, but I'm having some issues. I want to check, if restart() function has been called.
My code works like this, it's waiting for the data, and if there's no data it's calling the same function again. Basically something like a loop.
myCode.js file:
module.exports = {
getSomething: async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("");
}, 1000);
});
},
doSomething: async () => {
const data = await module.exports.getSomething();
if (!data) {
return module.exports.restart();
}
return data;
},
restart: async () => {
return module.exports.doSomething();
}
};
myCode.test.js file:
const myCode = require("./exampleCode")
describe("test", () => {
test("Is it doing something more than once?", async () => {
const restartSpy = jest.spyOn(myCode, 'restart');
myCode.doSomething()
expect(restartSpy).toHaveBeenCalledTimes(1);
})
})
My problem is that expect(restartSpy).toHaveBeenCalledTimes(1); is returning false.
The question is - what I'm doing wrong? Is there a way to test this code?
The main problem here is the lack of await before myCode.doSomething(). All your functions are asynchronous, so you need to wait for them to finish before checking the spy:
await myCode.doSomething();
Another issue is the fact that it's an infinite recursion loop - jest will timeout after 5000ms (by default) if you won't modify the code that is calling restart, for example:
doSomething: async (restartCounter = 0) => {
const data = await module.exports.getSomething();
if (!data && ++restartCounter < 2) {
return module.exports.restart(restartCounter);
}
return data;
},
restart: async (restartCounter) => {
return module.exports.doSomething(restartCounter);
}
Actually, I've found a workaround.
describe("test", () => {
test("Is it doing something more than once?", async () => {
myCode.restart = jest.fn()
const restartSpy = jest.spyOn(myCode, 'restart');
await myCode.doSomething()
expect(restartSpy).toHaveBeenCalledTimes(1);
})
})
I'm overwriting restart() function. So now, I'm able to add await to doSomething() function and it will no longer be inifinite loop. Now I can check if the restart function has been called

How to sleep a method in javascript method chaining

I am trying to make a method sleep(delay) in method chaining. For this I am using setTimeout with Promise. This will require any method following the sleep to be inside the then.
Right now I am calling the function like
lazyMan("John", console.log).eat("banana").sleep(5).then(d => {d.eat("apple");});.
Here is my code
function lazyMan(name, logFn) {
logFn(name);
return {
eat: function(val) {
console.log(val);
return this;
},
sleep: function(timer) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`Sleeping for ${timer} seconds`);
resolve(this);
}, timer * 1000);
}).then(d => this);
}
};
}
lazyMan("John", console.log)
.eat("banana")
.sleep(5)
.then(d => {
d.eat("apple");
});
Is there a way I can modify my function to call it like lazyMan("John", console.log).eat("banana").sleep(5).eat("apple") and get the output in same order
I have gone through Add a sleep method in a object method chain(JS)
You can keep a promise for your "task queue", so anything that needs to be done, will be added onto there via .then(). This provides a fluent API for scheduling stuff.
function lazyMan(name, logFn) {
logFn(name);
let taskQueue = Promise.resolve();
const addTask = f => {
taskQueue = taskQueue.then(f);
}
return {
eat: function(val) {
addTask(() => console.log(`Eating [${val}]`));
return this;
},
sleep: function(timer) {
addTask(() => new Promise((resolve, reject) => {
console.log(`Start sleeping for ${timer} seconds`);
setTimeout(() => {
console.log(`End sleeping for ${timer} seconds`);
resolve();
}, timer * 1000);
}))
return this;
}
};
}
lazyMan("John", console.log)
.eat("banana")
.sleep(5)
.eat("apple");
Note that this change means that every action is technically asynchronous. However, that's at least uniform, so it's less of a chance of a surprise when keeping it in mind.

Angular Observables return anonymous function

I have this method that I copied from a websocket tutorial but I don't understand the meaning of the "return () => { ... }" inside the observable ? Can someone explain me what is the purpose of that ?
public onMessage(topic: string, handler = SocketClientService.jsonHandler) : Observable<any> {
return this.connect().pipe(first(), switchMap(client => {
return new Observable<any>(observer => {
const subscription : StompSubscription = client.subscribe(topic, message => {
observer.next(handler(message));
});
return () => {
console.log("Unsubscribe from socket-client service");
client.unsubscribe(subscription .id);
}
});
}));
}
In order to create an Observable, you can use new Observable or a creation operator. See the following example:
const observable = new Observable(function subscribe(subscriber) {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
});
You can provide a function unsubscribe() to allow dispose of resources, and that function goes inside subscribe() as follows:
const observable = new Observable(function subscribe(subscriber) {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
return function unsubscribe() {
console.log('Clearing resources on observable');
};
});
Of course, you can use an arrow function expression to have:
const observable = new Observable((observer) => {
observer.next(1);
observer.next(2);
observer.next(3);
return () => {
console.log('Clearing resources on observable');
};
});
Try the following code to test the Observable:
const subscription = observable.subscribe(res => console.log('observable data:', res));
subscription.unsubscribe();
Finally, subscription.unsubscribe() is going to remove the socket connection in your example.
Find a project running with these examples here: https://stackblitz.com/edit/typescript-observable-unsubscribe
Let me know if that helps!

How to define a promise chain without using then method

I already looked for similar questions, but they are related to JQuery or any other library.
First, I wrote this:
const printIn1Sec = (value) => {
return new Promise(resolve => {
setTimeout(() => {
console.log(value);
resolve();
}, 1000)
});
};
And used it in this way:
printIn1Sec(1)
.then(() => printIn1Sec(2))
.then(() => printIn1Sec(3));
I think then is very important, because it allows us to execute something as soon as the promise is resolved.
But I was looking for something like this:
printIn1Sec(1)
.printIn1Sec(2)
.printIn1Sec(3);
I noticed I needed an object with access to this printIn1Sec method. So I defined a class:
class Printer extends Promise {
in1Sec(v) {
return this.then(() => this.getPromise(v));
}
getPromise(value) {
return new Printer(resolve => {
setTimeout(() => {
console.log(value);
resolve();
}, 1000)
})
}
}
And used it this way:
Printer.resolve().in1Sec(1).in1Sec(2).in1Sec(3);
I had to resolve the Promise from the beginning, in order to the start the chain. But it still bothers me.
Do you think, is there a way to get it working like the following?
printIn1Sec(1).printIn1Sec(2).printIn1Sec(3);
I was thinking in a new class or method, that could receive these values, store them, and finally start resolving the chain.
But it would require to call an aditional method at the end, to init with the flow.
If you really wanted to create a chainable interface as in your question, this would do it:
const printIn1Sec = (function() {
function setTimeoutPromise(timeout) {
return new Promise(resolve => setTimeout(resolve, 1000));
}
function printIn1Sec(value, promise) {
const newPromise = promise
.then(() => setTimeoutPromise(1000))
.then(() => console.log(value));
return {
printIn1Sec(value) {
return printIn1Sec(value, newPromise);
},
};
}
return value => printIn1Sec(value, Promise.resolve());
}());
printIn1Sec(1)
.printIn1Sec(2)
.printIn1Sec(3);
We just hide all the promise creation and chaining in an internal function. I split the code into smaller functions to make it a bit nicer looking.
You can try async and await
const printIn1Sec = (value) => {
return new Promise(resolve => {
setTimeout(() => {
console.log(value);
resolve();
}, 1000)
});
};
async function fun(){
await printIn1Sec(1);
await printIn1Sec(2);
await printIn1Sec(3);
}
fun();

Categories

Resources