How does one decide between promises, async awaits, and mapping operators like concatMap?
Here's my specific case, but I'm also curious about how you decide in general:
I am making an http call to my backend, and then I make another http call afterwards. When processing the json data from the second call, I need to use values that are returned by the first call. In this situation, is it better to use async await, a promise or concatMap? Also in general, what are the guidelines for deciding which to use?
Here is what I current have, using concatMap. (I am dynamically generating child components from my getTask http call, and each child component needs to have access to annotationFormats).
this.dashboardService.getAnnotationFormats()
.pipe(
concatMap(annotationFormats=> this.dashboardService.getTasks())
)
.subscribe(
(tasks)=>{
for(let task of tasks){
const componentFactory=this.CFR.resolveComponentFactory(DashboardItemComponent);
const componentRef=this.vc.createComponent(componentFactory);
componentRef.instance.task=task;
componentRef.instance.annotationFormats=annotationFormats;
componentRef.instance.compInteraction=this;
this.taskRef.push(componentRef);
}
}
);
Async/await and promises are basically the same with different syntax. Asynchronous code that will run once after some job has been finished.
As a rule, I would never never use none of those while using Angular. Angular comes with RxJS out of the box, which is so much more than promises. You can use RxJS for running async code once when a job has completed, but it also gives you the possibility of creating streams of data and manipulating them in so many different ways.
It does take a bit to fully understand RxJS and reactive programming but once you do you realize how much you can do with it.
In your case, I like to use the operator forkJoin, since the two requests seem independent from each other. You can give it a list of resources you want to obtain and will execute the async code in subscribe once they have all completed, which makes it perfect for http requests:
forkJoin({
annotationFormats: this.dashboardService.getAnnotationFormats(),
tasks: this.dashboardService.getTasks(),
})
.subscribe(
({tasks, annotationFormats})=>{
for(let task of tasks){
const componentFactory=this.CFR.resolveComponentFactory(DashboardItemComponent);
const componentRef=this.vc.createComponent(componentFactory);
componentRef.instance.task=task;
componentRef.instance.annotationFormats=annotationFormats;
componentRef.instance.compInteraction=this;
this.taskRef.push(componentRef);
}
}
);
Take your time to learn RxJS, I guarantee it will pay off. Whenever you are using RxJS and it feels too complex or wrong, that is because it probably is. Head to the RxJS documentation and look for something that might useful, and if you don't find anything a quick google search will probably get you the solution anyways. Point is, don't just use it blindly, always try to understand how it works.
I hope this is useful. :)
Edit:
For RxJS < 6.5, the syntax is a bit different:
forkJoin(
this.dashboardService.getTasks(),
this.dashboardService.getAnnotationFormats()
)
.subscribe(
([tasks, annotationFormats])=>{
for(let task of tasks){
const componentFactory=this.CFR.resolveComponentFactory(DashboardItemComponent);
const componentRef=this.vc.createComponent(componentFactory);
componentRef.instance.task=task;
componentRef.instance.annotationFormats=annotationFormats;
componentRef.instance.compInteraction=this;
this.taskRef.push(componentRef);
}
}
);
Notice we pass the resources as arguments, not as an object, and the result in the subscribe will be in an array form instead of an object too.
They have different use. async/await is used when you want to hold on a place where you have written some asynchronous code. while primises are tool to spot a place where async code is executed and invokes callback.
Related
How to call Async function in recursion actually I have Async method - async function getSSN(req,res,next) and inside this function block I need to call this function but when I call this method by code - return await getSSN(req,res,next) this code is not working for me in node js. Can anyone give me solution for that.?
So, you can't mix async/await with plain asynchronous callbacks. They do not work properly. Your async function getSSN() is not properly resolving when your request.get() finishes because that's just a plain asynchronous callback which the async function knows nothing about.
Instead, you need to use a promise-based request() option. Since, the request library is now deprecated and should not be used for new projects, I would suggest one of the alternatives that are all based on promises already. My favorite is the got() library, but you can look at the list of alternatives and pick the one that has a programming style you like.
In addition, your getSSN() function has a bunch of side effects (modifying higher scoped variables). This is not a good way to program, particularly for asynchronous operations because the outside world generally doesn't know when things are done and when the higher scoped variables have the values in them you want them to. You should make getSSN() return a promise that resolves to its result and then have the caller use that result to modify the higher scoped variables. Again, if you showed us the rest of the coding context here, we could suggest a better overall way to do this. Please notice here that you're just not providing enough code for us to be able to show you the best way to write this code. That should be a general lesson for stackoverflow. Err on the side of giving us more than you think and we can then often make suggestions and improvements far beyond what you even know to ask about.
Here's your function with all the ill-adivsed side effects still in it (because you haven't shown us the rest of the code) using got():
async function getSSN(next) {
const result = await got('idms.dealersocket.com/api/account/…').json();
if (count <= totalpage) {
const data = Object.assign({}, result.Data);
const len = Object.keys(data).length;
for (var i = 0; i <= len; i++) {
ssn.push(data[i].Row.Borrower1SSN);
}
count++;
}
}
Now, getSSN() will return a promise that resolves or rejects when the network request is finished.
Can anyone explain when to use async and await?
I want to write a method in angular application class, which will wait for the response of API call. Is it good to use Promise instead?
If both of them are asynchronous then when to use Promise instead of an async function?
What are observables? How they differ from Promises?
There are two branches in the question.
What are async functions, how they are different from promise constructor and what are observables.
When to use Observables and When to use Promises/Async functions.
I know this can be long enough to fill a wiki page, but from a pragmatic point of view it can be answered and may be useful to actually create practical informative resources.
About the first branch.
Promise: is an object that wraps a value, you interact with the value through the then method of the promise. You can learn more about Promises itself in javascript in https://promisesaplus.com/. This is specially useful for asynchronous operations, because you can decouple what the operation is and what you're going to do with the result of such operation
Aync functions: an async function is a function that is decorated to be asynchronous through the async sentence. Within this function you can use await to unwrap values from promises, and the value you return is automatically wrapped by a Promise (so you don't have to explicitly return a promise). These are specially useful for asynchronous operations because you can decouple the controls of a set of asynchronous operations and the control flow of the combination of those operations. You can learn more about async functions in https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Sentencias/funcion_asincrona.
Observables: is an object that wraps a value that changes over time, normally this change is pictured as a sequence of values. You interact with the values using the subscribe method. You could learn more by using marble http://rxmarbles.com/ and the docs. I would also recommend this article https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
About the second branch: as always it depends on the situation and the problem.
You could use a Promise when you request a value from a REST API or an Async Reader, because it is a single value and a Promise is easy to work with, it has a low learning curve.
const getDataFromFile = (fileName) => new Promise(resolve => {
readFile(fileName, content => resolve(content);
});
You could use an Async function to do calculations and transformations from a value you request from various a REST APIs or simply functions that return promises
async function concatFiles(fileName1, fileName2) {
const content1 = await getDataFromFile(fileName1);
const content2 = await getDataFromFile(fileName2);
return content1 + content2; // or just `$`
}
You could use observables for values that will change over time, you can address these changes to events and can address the values to states of something. Like a select it will trigger a change and will wrap a value
Observable.fromEvent(selectElement, 'change').subscribe(e => console.log(e))
About the second branch: you use what fits on the problem
Now, Angular proposes an architecture trait, and maybe this architecture (or architecture in other frameworks) asks you to use observables, and you have to handle it. But if you can choose, just use what fits the problem better by simplifying it in reasonable parts.
Extra branch of the question or how does all those structures come from and why?
There are plenty of reasons of why promises, async functions and observables have been created, and all of this is related to reactive programming, asynchrony, non blocking design of programs among others.
Hope it helps.
I am using Rxjs Observables to handle nested ajax request like the following way:
Rx.Observable.fromPromise($.getJSON('list1.json'))
.switchMap(function responseA(aResponse){
/* processing aResponse*/
if(aResponse.fileName){
return Rx.Observable.fromPromise($.getJSON(aResponse.fileName));
}
return Rx.Observable.fromPromise($.getJSON('list2.json'));
})
.subscribe(function(finalResponse){
/* processing finalResponse */
});
But, as you know, it can also be done without using Observables and with only promises:
$.getJSON('list1.json')
.then(function responseA(aResponse){
/* processing aResponse*/
if(aResponse.fileName){
return $.getJSON(aResponse.fileName);
}
return $.getJSON('list2.json');
})
.then(function(finalResponse){
/* processing finalResponse */
});
Both code works, but it seems to me that it is more clean in terms of code to use promises.
Am I missing something here as I've heart that Rx Observable is more standard and efficient to handle asynchronous requests.
Which one (promise or Observable) will be the best in terms of code organization, convention and performances to handle ajax request ?
If I prefer to use Observable then which operators (switchMap/MergeMap) will be preferable in these kind of situation ?
Am I missing something here as I've heart that Rx Observable is more standard and efficient to handle asynchronous requests.
No, you're not missing anything. Rx is really useful but in that particular case promise based code is simpler.
In general, if you need a singular value - prefer a promise. If you need multiple values in/out - use observables (or the further ahead in spec async iterators).
Rx would be nice if you want to quickly need to add:
Retrying the requests if they failed (with Observable.defer).
Only caring about the last request.
If you need built in cancellation.
It's worth mentioning - promises can do all that if you use a library. It's not a fundamental property of observables.
Rx really shines if your input is more than a single call. If you needed to make these calls whenever the user clicks something, ignore clicks on some condition, debounce it to 100ms and then only care about the last call - Rx would be really useful.
In this particular case - promises are simpler and fine. Your promise code can be simplified further:
$.getJSON('list1.json').then(x => $.getJSON(x.fileName || 'list2.json'))
There are couple of really good articles out there in web, here is couple of them, I hope those will help you to understand the difference properly.
What Promises Do That Observables Can’t
https://egghead.io/lessons/rxjs-rxjs-observables-vs-promises
I have an observer that goes like this.
var source = rx.Observable.fromEvent(eventAppeared.emitter, 'event')
.filter(mAndF.isValidStreamType)
.map(mAndF.transformEvent)
.share();
I then share it with a number of subscribers. These subscribers all take the event and perform some async operations on them.
so my subscribers are like
source.subscribe(async function(x) {
const func = handler[x.eventName];
if (func) {
await eventWorkflow(x, handler.handlerName, func.bind(handler));
}
});
There's a bit of extra stuff in there but I think the intent is clear.
I need every "handler" that handles this particular event to handle it and block till it gets back. Then process the next event.
What I've found with the above code is that it's just calling the event with out awaiting it and my handlers are stepping on themselves.
I've read a fair number of posts, but I can't really see how to do it. Most people are talking about making the observer awaitable. But that's not what I need is it? It seems like what I need is to make the observer awaitable. I can't find anything on that which usually means it's either super easy or a super ridiculous thing to do. I'm hoping for the former.
Please let me know if you need any further clarification.
---update---
what I have realized is that what I need is a fifo queue or buffer ( first in first out ), sometimes referred to as back pressure. I need all messages processed in order and only when the preceding message is done processing.
---end update---
at first I thought it was cuz I was using rx 2.5.3 but I just upgraded to 4.1.0 and it's still not synchronous.
There's no way to tell a source observable to put events on hold from within a subscribe, it just lets us "observe" incoming events. Asynchronous things should be managed via Rx operators.
For example, to let your asynchronous handlers process events sequentially, you could try to use concatMap operator:
source
.concatMap(x => {
const func = handler[x.eventName];
return func ?
eventWorkflow(x, handler.handlerName, func.bind(handler)) :
Rx.Observable.empty();
})
.subscribe();
Note that in the example above await is not needed as concatMap knows how to deal with a promise which eventWorkflow returns: concatMap converts it to an observable and waits until the observable completes before proceeding with the next event.
So ultimately what I have found is that what I need is more accurately described as a fifo queue or buffer. I need the messages to wait until the previous message is done processing.
I have also pretty certain that rxjs doesn't offer this ( sometimes referred to as backpressure ). So what I have done is to just import a fifo queue and hook it to each subscriber.
I am using concurrent-queue which so far seems to be working pretty well.
I have a function,
Edit1 - Updated function with real one because the previous one was simplified synchronous function and the code would have worked as correctly pointed by #AlexMA in the comments
'returnSuccessOrFailure': function () {
return driver.findElement(wd.By.css('div#button')).then(function (button) {
return button.getAttribute('class').then(function (status) {
return status;
});
});
}
In my node.js test, my assertion is failing because the assert is called before returnSuccessOrFailure finishes execution.
var value = returnSuccessOrFailure();
assert.equal(value,'success', 'Looks like something failed');
If I implement a promise in returnSuccessOrFailure and chain my assert then that works. My question is do I have to implement promises all the time for such situations to block the execution? I am new to Javascript and the async nature of it and any insight when to use promises and when not to would be useful.
you don't have to "implement a promise" in, just return the one you already have:
returnSuccessOrFailure': function () {
return driver.findElement(wd.By.css('div#button')).then(function (button) {
...
but then, yes, you do still need to put your assert in a done handler
returnSuccessOrFailure().done(function(value) {
assert.equal(value,'success', 'Looks like something failed');
}
Chaining you asserts will not only make it work but will also make for more readable code. Knowing what happens in what order can be useful when going back to refactor. Not only that but the structure of callbacks/promises also allow for easily written timer tests.
Also, since your test needs to have the current state of execution, it is more than likely that writing tests with asserts in callbacks is what you will need anyway.
My question is do I have to implement promises all the time for such situations to block the execution?
Notice that promises don't block the execution. They defer the execution of code that depends on the result, notice that you're still chaining callbacks on them.
I am new to Javascript and the async nature of it and any insight when to use promises and when not to would be useful.
Promises are useful wherever you have some code that might run asynchronously and needs to pass back an asynchronous result. Otherwise you would need to use callbacks, which are way more ugly than promises.
This is part of code contracts and representing preconditions (what holds before you execute), postconditions (what holds after you execute), and object invariants (what can not change). JavaScript does not have native support for this, but you can use third party libraries (Cerny.js, ecmaDebug, jsContract, or jscategory)
I think it depends on your coding style, is it EAFP(Easier to ask for forgiveness than permission) or LBYL(Look before you leap). Both are viable! In most compiled languages you would use LBYL. However in Python for example you would use EAFP.
Generally if you know you will fail you want to fail fast. If you like to use assertions to ensure code fails fast it is up to you.