Call firebase httpsCallable multiple times - javascript

Calling foo two times creates two subscribers and that is not ok but even so the second call of foo seems to get stuck somewhere because console.log gets called only one time.
I know that I should not subscribe in this manner but I really do not see the solution to get myFunc to output the second result
const myFunc = functions.httpsCallable('myFunc')
function foo(inData){
myFunc({data:inData}).subscribe((res)=>{
console.log(res)
})
}
foo('aaaaa')
foo('bbbbb')
second attempt still no luck
myFunc(data){
return functions.httpsCallable('myFunc')(data)
}
async function foo(inData){
let res = await lastValueFrom(myFunc({data:inData}))
console.log(res)
}
foo('aaaaa')
foo('bbbbb')

The HttpsCallable function returns a promise by default. As you can see in this related question , there are a few differences between promises and observables, as it seems that you are already working with observables, I would try to convert the promise received from the function to an observable using this method, as suggested in this other question:
import { from } from 'rxjs';
const observable = from(promise);
Although, there are other methods suggested as well in the same question.
I would also like to point you to the Using observables to pass values, I think you might not have shared how you are creating the observer. I'm just guessing but you should also unsubscribe to clean up data ready for the next subscription. Also, missing next notification that is required.
As an extra, I would say that if you are not obligated to use observables, handle it as a promise.

Related

How to control C# Task (async/await in same way as javascript Promise)?

I'm js developer and jumped to C#. I'm learning async/await/Task in C# and can't understand how to control C# Task.
In javascript I can save Promise resolve handler to call it later (and resolve promise), for example, to organize communication between some "badly connected" app parts (request doesn't returns result, but result is sent separately and fires some "replyEvent"), and do something like this:
// javascript
const handlers = {}
// event firing on reply
const replyEventListener = (requestId, result) => {
if (handlers[requestId]) {
handlers[requestId](result)
delete handlers[requestId]
}
}
const requestFunction = (id, params) => new Promise(resolve => {
// handler is saved to use later from "outside"
handlers[id] = resolve;
// do required request
makeRequest(params)
})
// .. somewhere in code request becomes simple awaitable
const resultOfRequest = await requestFunction(someUniqueId)
How can I do same with C# Task?
I think the philosophy behind Promise (in JS) and Task (in C#) is different.
We don't implement them exactly the same way.
Read the documentation on the MSDN :
Task Class - Remarks
Task<TResult> Class
You must empty your cup to be able to fill it again.
A good article in MSDN is the following which shows examples of how Tasks can be used like Promises in the sense that you can start them and then await them later.
Asynchronous programming with async and await
If you want to await a Task in C# like you would a Promise in JS, you would do the following:
Create a method or function that returns a Task. Usually this will be a Task of some class object. In the article above, it references creating breakfast as an analogy, so you can define FryEggsAsync as a method that takes in an int number of how many eggs to fry and returns a Task<Egg>. The C# convention is to end any function or method name with Async to indicate that a Task is being returned.
Create your Task, which is similar to a Promise in JS, so you could do var eggsTask = FryEggsAsync(2), which would store a Task<Egg> in eggsTask, that you can then await or pass to other functions as needed.
To await your Task to resolve it and get the result, you would simply do await eggsTask.
You can also use Task.WaitAll to await multiple Tasks at once, similar to Promise.all in JS, by passing in an array of Tasks as an argument to that method call. See the Task.WaitAll documentation for some examples of this. The difference here though is that the results are stored separately in each task passed to Task.WaitAll, instead of aggregated together into a results array like in JS with Promise.all, but if you need to await multiple Tasks then this will be an easier way to do so.

How can I force one block of code to wait until an API call finishes in Typescript?

I am making an API call and want the code after the call to not run until the API call finishes.
I have a function, this.api_call, which calls an API and returns an array, returnValue, after the API call is complete.
let returnValue = this.api_call(data);
//This line should not run until returnValue has been set
this.otherFunction(returnValue[0], returnValue[1]);
How can I make just that one line wait before running? I want other code to still be able to run before the API call completes, it's just that one line that should wait.
that's where Promises come in, If your function this.api_call(data) returns a Promise, you can then call the then function on it, with a callback, and this callback will be run only after the promise has resolve.
this.api_call(data).then((returnValue) => {
this.otherFunction(returnValue[0], returnValue[1]);
});
You can also use RxJS's observable, which lets you alter your data before returing it using pipe function. If you are using observable, make sure your subscribe to your observable otherwise it will never be fired.
If your this.api_call(data) function is returning an observable ( usually the case if you use Angular), use it like that:
this.api_call(data).subscribe((returnValue) => {
this.otherFunction(returnValue[0], returnValue[1]);
});
There is also a way to use async / await keywords but i'm not a pro in this concept so i'll let somebody else answer that.
There are multiple ways to achieve it, the simplest one is async / await syntax of Promise:
async function myAsyncFunction(): Promise<void> {
let returnValue = await this.api_call(data);
this.otherFunction(returnValue[0], returnValue[1]);
}
this.api_call(data) have to return a Promise<ArrayLike<...>> in your example.

Loading data into a React Native FlatList

I fully admit that I'm pretty new to Reactive Native at this point so I anticipate this being an easy answer and a potentially stupid question :) In fact, this may not be a RN issue per se, as I'll explain below.
What I have is the following code:
class MyScreen extends React.Component {
constructor(inProps) {
super(inProps);
this.state = { listData : [ ] };
}
render() { return (
<View>
<FlatList data={ this.state.listData }
renderItem={ ({item}) =>
<Text>{item.firstName} {item.lastName}</Text>
}
/>
</View>
); }
async componentDidMount() {
const data = [ ];
let keys = await AsyncStorage.getAllKeys();
keys.forEach(async function(inKey) {
let obj = await AsyncStorage.getItem(inKey);
obj = JSON.parse(obj);
data.push(obj);
});
this.setState({ listData : data });
};
}
The goal is simply to load the data from AsyncStorage and dump it in the list. Fairly basic it would seem, right? Unfortunately, I can't get it to work: the list is empty.
Now, to cover the stupid things: yes, there is indeed data stored and yes, it's in the correct form (I know this because if I simply grab ONE SPECIFIC item and push() it into data then it appears in the list as expected).
In fact, I know what the problem is: it's that the setState() call is executing before the keys.forEach() call completes. I know this because if I replace the setState() call with this:
setTimeout(function() {
this.setState({ listData : data });
}.bind(this), 1000);
...then suddenly my list is populated as expected (I can also throw some console.log()'s in there and see that the one after the keys.forEach() call actually executes BEFORE those inside the keys.forEach()). I also know that obviously the getItem() call is waiting before the JSON.parse() is called, otherwise this wouldn't work at all.
In other words: I know this is caused by the asynchronous nature of this code. What I can't seem to figure out is how to write it properly to avoid this.
I'm looking at it and I'm thinking "well, keys.forEach() is a blocking call, so how could it possibly not complete before the setState() call, ESPECIALLY given the async usage on the keys.forEach() callback AND the await usage on the getItem() call inside?"... the only thought I had was to drop an async in front of the keys.forEach() call, but that doesn't make any difference.
So, it seems to be a basic JavaScript question in essence, but I can't seem to solve it... but on the other hand, I'm not sure if I'm trying to do this in a way that I fundamentally shouldn't be in RN land and maybe THAT'S the real problem.
Note that the data has to be pulled dynamically from AsyncStorage because of the flow through the application (adds are done on another screen), so it seems to me that trying to load it in componentDidMount() makes sense, I'm just getting hung up with the asynchronous nature of the calls involved.
Any suggestions?
Thanks!
EDIT: I should also mention that I know one way I can solve this is to just remove the asynchronous nature entirely: rather than storing individual data items, instead store everything in a single object in AsyncStorage. Then I can read the ONE item, which would be an array (or would contain an array), then the only asynchronous part is the getItem() call, but I can use the callback version of that and make it work that way... and I'm not against that approach at all, but at this point I really want to understand what I'm doing wrong if for no other reason than to learn something because this seems like it SHOULD work :)
keys.forEach execute the code in its own scope (in its own callback function), and that breaks your async / await pair.
Do this instead:
for (let inKey of keys) {
let obj = await AsyncStorage.getItem(inKey);
obj = JSON.parse(obj);
data.push(obj);
}
If you really want forEach, you have to write your own version that returns Promise, so you can hook await on it for example:
await keys.awaitableForEach(async function(inKey) {

RXJS Subject, return the same value on every first subscribe

I know I need to use startWith, but still trying to figure out how to use it. If I just do Subject.create().startWith("Some Value), it turns the Subject into a Observable, and I can't use next to emit.
So multiple subscribers should be able subscribe to it. Should be able to call next on the Subject. Going through the docs of Subject.create(), but it's going slow.
Edit:
I got it to work after using the accepted solution. The reason why it wasn't working before was because I put the .next call inside the subscription.
Eg:
observable.subscribe((res) => {
// do something
s.next('another res');
}
This creates an infinite loop, and I think RXJS prevented it? Anyway, I put the next in there for debug purposes. I moved it outside of that subscribe block and now and initial result emits, then when next is called, whatever was inside subscribe emit again.
You should avoid using Subject.create() and use just Subject(). See: Subject vs AnonymousSubject
Just keep a reference to the Subject instance and another reference to the Observable chain you need:
let s = new Subject();
let observable = s.startWith("Some initial message");
observable.subscribe(...);
s.next('whatever');

How do I use observable and observer in angular?

I come from a synchronous programming background and I am having a hard time understanding observables.
Here is an extract of my service/provider (Ionic 2 project)
return this.http.get(`${this.serverApi}`)
.map(res => <Response[]>res.json());
and I will subscribe to that from the LoginPage. I have several questions regarding this.
Does the above code return an observable/ observer even if I didn't declare it as such?
The response is JSON. How do I do some checking/processing of the JSON and perform some action like if
res.auth_token==true
then do
localStorage.setItem(res.auth_token)
I believe it should be done in the provider class. Just a typical hint/example will be awesome.
Does the request actually happen when it hits the subscribe method?
Creating and returning Observable from Angular 2 Service mentions Subject and ReplaySubject. Should I use them instead?
The code will return an Observable
You can change the callback body to a block and add as much code as you want
return this.http.get(`${this.serverApi}`)
.map(res => {
let x = <Response[]>res.json();
// do something with x
res.auth_token == true;
return res; // with a block body an explicit`return` is required
});
Yes, calling .subscribe() will execute the http.get() and then all subsequent operators when the response arrives. Without .subscribe() nothing will happen.
Note: Some Angular APIs expect an Observable, in this case you must not call subscribe() because subscribe() returns a Subscription, not an Observable.
it depends what you try to accomplish. If you use http.get(), you already get an observable and there is no need for Subject, ReplaySubject, or any of the other possibilities.

Categories