checking if rxjs observable is complete - rxjs

I have a class that when instantiated makes some web service calls, pseudo code below:
Rx.Observable.fromPromise(jQuery.getJSON('https://api.github.com/users'))
.flatMap(function () {
return Rx.Observable.fromPromise(jQuery.getJSON('https://api.github.com/users'));
});
The same class is listening for an onclick event.
When this even is triggered, if the original web service calls are complete: do something
If they are not complete, wait for them to complete, before doing something.
I was wondering how to achieve this with the rxjs approach? rather than setting variables and using if statements.

I would refer to this as an Asynchronous Gate.
These are actually pretty easy to do with Rx.
You will need to cache the web service calls observable sequences.
Then in other calls that are predicated on these being complete, you simply flatMap off their results.
As these are from Promises I believe the result is retained for late subscribers, but if not then you just need to replay(1) the sequences.
So in psudeo code
var startUpData = Rx.Observable.fromPromise(jQuery.getJSON('https://api.github.com/users'))
.flatMap(function () {
return Rx.Observable.fromPromise(jQuery.getJSON('https://api.github.com/users'));
});
var events = Rx.Observable....//Your event wired up here.
//When an event
events
.flatMap(function(evt){
//Wait until the startUpData yeilds, but pass on the evt data instead.
return startUpData.map(function(){ return evt;})
//do something here knowing that your event has fired, but the web services have also completed.
.subscribe();
You can see Matt Barrett explain an Async gate in this video at about 51minutes in to this video - https://youtu.be/Tp5mRlHwZ7M?t=51m30s
You may also want to consider the switch operator incase you don't want overlapping events

I believe withLatestFrom or combineLatest will do what you're asking.
Depending on if you wish to only allow the button to be clicked once with the data provided from the service you could use withLatestFrom. If you wish to allow the button to continued to be clicked using the data previously provided by the service you can use combineLatest
const futureEvent$ = Rx.Observable.timer(3000);
const btnClick$ = Rx.Observable
.fromEvent(document.querySelector('button'), 'click');
const futureAndBtnClick$ = futureEvent$.combineLatest(btnClick$);
futureAndBtnClick$.subscribe(x => console.log('click + future stuff happened'));
jsbin example

Related

Is there a way to modify a global variable with the value of an onreadystatechange event? [duplicate]

Given the following examples, why is outerScopeVar undefined in all cases?
var outerScopeVar;
var img = document.createElement('img');
img.onload = function() {
outerScopeVar = this.width;
};
img.src = 'lolcat.png';
alert(outerScopeVar);
var outerScopeVar;
setTimeout(function() {
outerScopeVar = 'Hello Asynchronous World!';
}, 0);
alert(outerScopeVar);
// Example using some jQuery
var outerScopeVar;
$.post('loldog', function(response) {
outerScopeVar = response;
});
alert(outerScopeVar);
// Node.js example
var outerScopeVar;
fs.readFile('./catdog.html', function(err, data) {
outerScopeVar = data;
});
console.log(outerScopeVar);
// with promises
var outerScopeVar;
myPromise.then(function (response) {
outerScopeVar = response;
});
console.log(outerScopeVar);
// with observables
var outerScopeVar;
myObservable.subscribe(function (value) {
outerScopeVar = value;
});
console.log(outerScopeVar);
// geolocation API
var outerScopeVar;
navigator.geolocation.getCurrentPosition(function (pos) {
outerScopeVar = pos;
});
console.log(outerScopeVar);
Why does it output undefined in all of these examples? I don't want workarounds, I want to know why this is happening.
Note: This is a canonical question for JavaScript asynchronicity. Feel free to improve this question and add more simplified examples which the community can identify with.
One word answer: asynchronicity.
Forewords
This topic has been iterated at least a couple of thousands of times here in Stack Overflow. Hence, first off I'd like to point out some extremely useful resources:
#Felix Kling's answer to "How do I return the response from an asynchronous call?". See his excellent answer explaining synchronous and asynchronous flows, as well as the "Restructure code" section.
#Benjamin Gruenbaum has also put a lot of effort into explaining asynchronicity in the same thread.
#Matt Esch's answer to "Get data from fs.readFile" also explains asynchronicity extremely well in a simple manner.
The answer to the question at hand
Let's trace the common behavior first. In all examples, the outerScopeVar is modified inside of a function. That function is clearly not executed immediately; it is being assigned or passed as an argument. That is what we call a callback.
Now the question is, when is that callback called?
It depends on the case. Let's try to trace some common behavior again:
img.onload may be called sometime in the future when (and if) the image has successfully loaded.
setTimeout may be called sometime in the future after the delay has expired and the timeout hasn't been canceled by clearTimeout. Note: even when using 0 as delay, all browsers have a minimum timeout delay cap (specified to be 4ms in the HTML5 spec).
jQuery $.post's callback may be called sometime in the future when (and if) the Ajax request has been completed successfully.
Node.js's fs.readFile may be called sometime in the future when the file has been read successfully or thrown an error.
In all cases, we have a callback that may run sometime in the future. This "sometime in the future" is what we refer to as asynchronous flow.
Asynchronous execution is pushed out of the synchronous flow. That is, the asynchronous code will never execute while the synchronous code stack is executing. This is the meaning of JavaScript being single-threaded.
More specifically, when the JS engine is idle -- not executing a stack of (a)synchronous code -- it will poll for events that may have triggered asynchronous callbacks (e.g. expired timeout, received network response) and execute them one after another. This is regarded as Event Loop.
That is, the asynchronous code highlighted in the hand-drawn red shapes may execute only after all the remaining synchronous code in their respective code blocks have executed:
In short, the callback functions are created synchronously but executed asynchronously. You can't rely on the execution of an asynchronous function until you know it has been executed, and how to do that?
It is simple, really. The logic that depends on the asynchronous function execution should be started/called from inside this asynchronous function. For example, moving the alerts and console.logs inside the callback function would output the expected result because the result is available at that point.
Implementing your own callback logic
Often you need to do more things with the result from an asynchronous function or do different things with the result depending on where the asynchronous function has been called. Let's tackle a bit more complex example:
var outerScopeVar;
helloCatAsync();
alert(outerScopeVar);
function helloCatAsync() {
setTimeout(function() {
outerScopeVar = 'Nya';
}, Math.random() * 2000);
}
Note: I'm using setTimeout with a random delay as a generic asynchronous function; the same example applies to Ajax, readFile, onload, and any other asynchronous flow.
This example clearly suffers from the same issue as the other examples; it is not waiting until the asynchronous function executes.
Let's tackle it by implementing a callback system of our own. First off, we get rid of that ugly outerScopeVar which is completely useless in this case. Then we add a parameter that accepts a function argument, our callback. When the asynchronous operation finishes, we call this callback, passing the result. The implementation (please read the comments in order):
// 1. Call helloCatAsync passing a callback function,
// which will be called receiving the result from the async operation
helloCatAsync(function(result) {
// 5. Received the result from the async function,
// now do whatever you want with it:
alert(result);
});
// 2. The "callback" parameter is a reference to the function which
// was passed as an argument from the helloCatAsync call
function helloCatAsync(callback) {
// 3. Start async operation:
setTimeout(function() {
// 4. Finished async operation,
// call the callback, passing the result as an argument
callback('Nya');
}, Math.random() * 2000);
}
Code snippet of the above example:
// 1. Call helloCatAsync passing a callback function,
// which will be called receiving the result from the async operation
console.log("1. function called...")
helloCatAsync(function(result) {
// 5. Received the result from the async function,
// now do whatever you want with it:
console.log("5. result is: ", result);
});
// 2. The "callback" parameter is a reference to the function which
// was passed as an argument from the helloCatAsync call
function helloCatAsync(callback) {
console.log("2. callback here is the function passed as argument above...")
// 3. Start async operation:
setTimeout(function() {
console.log("3. start async operation...")
console.log("4. finished async operation, calling the callback, passing the result...")
// 4. Finished async operation,
// call the callback passing the result as argument
callback('Nya');
}, Math.random() * 2000);
}
Most often in real use cases, the DOM API and most libraries already provide the callback functionality (the helloCatAsync implementation in this demonstrative example). You only need to pass the callback function and understand that it will execute out of the synchronous flow and restructure your code to accommodate for that.
You will also notice that due to the asynchronous nature, it is impossible to return a value from an asynchronous flow back to the synchronous flow where the callback was defined, as the asynchronous callbacks are executed long after the synchronous code has already finished executing.
Instead of returning a value from an asynchronous callback, you will have to make use of the callback pattern, or... Promises.
Promises
Although there are ways to keep the callback hell at bay with vanilla JS, promises are growing in popularity and are currently being standardized in ES6 (see Promise - MDN).
Promises (a.k.a. Futures) provide a more linear, and thus pleasant, reading of the asynchronous code, but explaining their entire functionality is out of the scope of this question. Instead, I'll leave these excellent resources for the interested:
JavaScript Promises - HTML5 Rocks
You're Missing the Point of Promises - domenic.me
More reading material about JavaScript asynchronicity
The Art of Node - Callbacks explains asynchronous code and callbacks very well with vanilla JS examples and Node.js code as well.
Note: I've marked this answer as Community Wiki. Hence anyone with at least 100 reputations can edit and improve it! Please feel free to improve this answer or submit a completely new answer if you'd like as well.
I want to turn this question into a canonical topic to answer asynchronicity issues that are unrelated to Ajax (there is How to return the response from an AJAX call? for that), hence this topic needs your help to be as good and helpful as possible!
Fabrício's answer is spot on; but I wanted to complement his answer with something less technical, which focusses on an analogy to help explain the concept of asynchronicity.
An Analogy...
Yesterday, the work I was doing required some information from a colleague. I rang him up; here's how the conversation went:
Me: Hi Bob, I need to know how we foo'd the bar'd last week. Jim wants a report on it, and you're the only one who knows the details about it.
Bob: Sure thing, but it'll take me around 30 minutes?
Me: That's great Bob. Give me a ring back when you've got the information!
At this point, I hung up the phone. Since I needed information from Bob to complete my report, I left the report and went for a coffee instead, then I caught up on some email. 40 minutes later (Bob is slow), Bob called back and gave me the information I needed. At this point, I resumed my work with my report, as I had all the information I needed.
Imagine if the conversation had gone like this instead;
Me: Hi Bob, I need to know how we foo'd the bar'd last week. Jim want's a report on it, and you're the only one who knows the details about it.
Bob: Sure thing, but it'll take me around 30 minutes?
Me: That's great Bob. I'll wait.
And I sat there and waited. And waited. And waited. For 40 minutes. Doing nothing but waiting. Eventually, Bob gave me the information, we hung up, and I completed my report. But I'd lost 40 minutes of productivity.
This is asynchronous vs. synchronous behavior
This is exactly what is happening in all the examples in our question. Loading an image, loading a file off disk, and requesting a page via AJAX are all slow operations (in the context of modern computing).
Rather than waiting for these slow operations to complete, JavaScript lets you register a callback function which will be executed when the slow operation has completed. In the meantime, however, JavaScript will continue to execute other code. The fact that JavaScript executes other code whilst waiting for the slow operation to complete makes the behaviorasynchronous. Had JavaScript waited around for the operation to complete before executing any other code, this would have been synchronous behavior.
var outerScopeVar;
var img = document.createElement('img');
// Here we register the callback function.
img.onload = function() {
// Code within this function will be executed once the image has loaded.
outerScopeVar = this.width;
};
// But, while the image is loading, JavaScript continues executing, and
// processes the following lines of JavaScript.
img.src = 'lolcat.png';
alert(outerScopeVar);
In the code above, we're asking JavaScript to load lolcat.png, which is a sloooow operation. The callback function will be executed once this slow operation has done, but in the meantime, JavaScript will keep processing the next lines of code; i.e. alert(outerScopeVar).
This is why we see the alert showing undefined; since the alert() is processed immediately, rather than after the image has been loaded.
In order to fix our code, all we have to do is move the alert(outerScopeVar) code into the callback function. As a consequence of this, we no longer need the outerScopeVar variable declared as a global variable.
var img = document.createElement('img');
img.onload = function() {
var localScopeVar = this.width;
alert(localScopeVar);
};
img.src = 'lolcat.png';
You'll always see a callback is specified as a function, because that's the only* way in JavaScript to define some code, but not execute it until later.
Therefore, in all of our examples, the function() { /* Do something */ } is the callback; to fix all the examples, all we have to do is move the code which needs the response of the operation into there!
* Technically you can use eval() as well, but eval() is evil for this purpose
How do I keep my caller waiting?
You might currently have some code similar to this;
function getWidthOfImage(src) {
var outerScopeVar;
var img = document.createElement('img');
img.onload = function() {
outerScopeVar = this.width;
};
img.src = src;
return outerScopeVar;
}
var width = getWidthOfImage('lolcat.png');
alert(width);
However, we now know that the return outerScopeVar happens immediately; before the onload callback function has updated the variable. This leads to getWidthOfImage() returning undefined, and undefined being alerted.
To fix this, we need to allow the function calling getWidthOfImage() to register a callback, then move the alert'ing of the width to be within that callback;
function getWidthOfImage(src, cb) {
var img = document.createElement('img');
img.onload = function() {
cb(this.width);
};
img.src = src;
}
getWidthOfImage('lolcat.png', function (width) {
alert(width);
});
... as before, note that we've been able to remove the global variables (in this case width).
Here's a more concise answer for people that are looking for a quick reference as well as some examples using promises and async/await.
Start with the naive approach (that doesn't work) for a function that calls an asynchronous method (in this case setTimeout) and returns a message:
function getMessage() {
var outerScopeVar;
setTimeout(function() {
outerScopeVar = 'Hello asynchronous world!';
}, 0);
return outerScopeVar;
}
console.log(getMessage());
undefined gets logged in this case because getMessage returns before the setTimeout callback is called and updates outerScopeVar.
The two main ways to solve it are using callbacks and promises:
Callbacks
The change here is that getMessage accepts a callback parameter that will be called to deliver the results back to the calling code once available.
function getMessage(callback) {
setTimeout(function() {
callback('Hello asynchronous world!');
}, 0);
}
getMessage(function(message) {
console.log(message);
});
Promises
Promises provide an alternative which is more flexible than callbacks because they can be naturally combined to coordinate multiple async operations. A Promises/A+ standard implementation is natively provided in node.js (0.12+) and many current browsers, but is also implemented in libraries like Bluebird and Q.
function getMessage() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Hello asynchronous world!');
}, 0);
});
}
getMessage().then(function(message) {
console.log(message);
});
jQuery Deferreds
jQuery provides functionality that's similar to promises with its Deferreds.
function getMessage() {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve('Hello asynchronous world!');
}, 0);
return deferred.promise();
}
getMessage().done(function(message) {
console.log(message);
});
async/await
If your JavaScript environment includes support for async and await (like Node.js 7.6+), then you can use promises synchronously within async functions:
function getMessage () {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Hello asynchronous world!');
}, 0);
});
}
async function main() {
let message = await getMessage();
console.log(message);
}
main();
To state the obvious, the cup represents outerScopeVar.
Asynchronous functions be like...
The other answers are excellent and I just want to provide a straight forward answer to this. Just limiting to jQuery asynchronous calls
All ajax calls (including the $.get or $.post or $.ajax) are asynchronous.
Considering your example
var outerScopeVar; //line 1
$.post('loldog', function(response) { //line 2
outerScopeVar = response;
});
alert(outerScopeVar); //line 3
The code execution starts from line 1, declares the variable and triggers and asynchronous call on line 2, (i.e., the post request) and it continues its execution from line 3, without waiting for the post request to complete its execution.
Lets say that the post request takes 10 seconds to complete, the value of outerScopeVar will only be set after those 10 seconds.
To try out,
var outerScopeVar; //line 1
$.post('loldog', function(response) { //line 2, takes 10 seconds to complete
outerScopeVar = response;
});
alert("Lets wait for some time here! Waiting is fun"); //line 3
alert(outerScopeVar); //line 4
Now when you execute this, you would get an alert on line 3. Now wait for some time until you are sure the post request has returned some value. Then when you click OK, on the alert box, next alert would print the expected value, because you waited for it.
In real life scenario, the code becomes,
var outerScopeVar;
$.post('loldog', function(response) {
outerScopeVar = response;
alert(outerScopeVar);
});
All the code that depends on the asynchronous calls, is moved inside the asynchronous block, or by waiting on the asynchronous calls.
In all these scenarios outerScopeVar is modified or assigned a value asynchronously or happening in a later time(waiting or listening for some event to occur),for which the current execution will not wait.So all these cases current execution flow results in outerScopeVar = undefined
Let's discuss each examples(I marked the portion which is called asynchronously or delayed for some events to occur):
1.
Here we register an eventlistner which will be executed upon that particular event.Here loading of image.Then the current execution continuous with next lines img.src = 'lolcat.png'; and alert(outerScopeVar); meanwhile the event may not occur. i.e, funtion img.onload wait for the referred image to load, asynchrously. This will happen all the folowing example- the event may differ.
2.
Here the timeout event plays the role, which will invoke the handler after the specified time. Here it is 0, but still it registers an asynchronous event it will be added to the last position of the Event Queue for execution, which makes the guaranteed delay.
3.
This time ajax callback.
4.
Node can be consider as a king of asynchronous coding.Here the marked function is registered as a callback handler which will be executed after reading the specified file.
5.
Obvious promise (something will be done in future) is asynchronous. see What are the differences between Deferred, Promise and Future in JavaScript?
https://www.quora.com/Whats-the-difference-between-a-promise-and-a-callback-in-Javascript
The short answer is : asynchronicity.
Why asynchronous is needed?
JavaScript is single-threaded, meaning that two bits of the script cannot run at the same time; they have to run one after another. In browsers, JavaScript shares a thread with a load of other stuff that differs from browser to browser. But typically JavaScript is in the same queue as painting, updating styles, and handling user actions (such as highlighting text and interacting with form controls). Activity in one of these things delays the others.
You've probably used events and callbacks to get around this. Here are events:
var img1 = document.querySelector('.img-1');
img1.addEventListener('load', function() {
// image loaded
console.log("Loaded");
});
img1.addEventListener('error', function() {
// error caught
console.log("Error printed");
});
<img class="img-1" src="#" alt="img">
This isn't sneezy at all. We get the image, add a couple of listeners, then JavaScript can stop executing until one of those listeners is called.
Unfortunately, in the example above, it's possible that the events happened before we started listening for them, so we need to work around that using the "complete" property of images:
var img1 = document.querySelector('.img-1');
function loaded() {
// image loaded
console.log("Loaded");
}
if (img1.complete) {
loaded();
} else {
img1.addEventListener('load', loaded);
}
img1.addEventListener('error', function() {
// error caught
console.log("Error printed");
});
<img class="img-1" src="#" alt="img">
This doesn't catch images that errored before we got a chance to listen for them; unfortunately, the DOM doesn't give us a way to do that. Also, this is loading one image. Things get even more complex if we want to know when a set of images have loaded.
Events aren't always the best way
Events are great for things that can happen multiple times on the same object— keyup, touchstart etc. With those events, you don't really care about what happened before you attached the listener.
The two main ways to do it correctly: are callbacks and promises.
Callbacks
Callbacks are functions that are passed inside the arguments of other functions, this procedure is valid in JavaScript because functions are objects and objects can be passed as arguments to functions. The basic structure of the callback function looks something like this:
function getMessage(callback) {
callback();
}
function showMessage() {
console.log("Hello world! I am a callback");
}
getMessage(showMessage);
Promise
Although there are ways to keep the callback hell at bay with vanilla JS, promises are growing in popularity and are currently being standardized in ES6 (see Promise).
A promise is a placeholder representing the eventual result (value) of an asynchronous operation
the promise placeholder will be replaced by the result value (if successful) or reason for failure (if unsuccessful)
If you don't need to know when something happened, but just whether it happened or not, then a promise is what you are looking for.
A promise is a bit like an event listener, except that:
a promise can only succeed or fail once
a promise can't switch from fail to success, or vice versa
once you have a result, the promise is immutable
if a promise has succeeded or failed, and you later add a success/failure callback, the correct callback will be called
it doesn't matter that the event occurred before you added the callback
Note: Always return a result from a function inside a Promise, otherwise there's nothing for the subsequent function to act on.
Promise Terminology
A promise can be:
fulfilled: The action relating to the promise succeeded
the asynchronous operation has completed
the promise has a value
the promise will not change again
rejected: The action relating to the promise failed
the asynchronous operation failed
the promise will never be fulfilled
the promise has a reason indicating why the operation failed
the promise will not change again
pending: Hasn't fulfilled or rejected yet
the asynchronous operation hasn't been completed yet
can transition to fulfilled or rejected
settled: Has been fulfilled or rejected and is thus immutable
How to Create a Promise
function getMessage() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Hello world! I am a promise');
}, 0);
});
}
getMessage().then(function(message) {
console.log(message);
});

rxjs - Tap vs subscribe

In many articles I find that tap operator is a good way to perform side effects. My question is about a difference between performing side effects using subscribe and tap. Here are examples which are doing actually the same:
this.store$
.pipe(tap(x => {
this.store = x;
}));
this.store$
.subscribe(x => {
this.store = x;
});
Is there any difference in the performance or is there any reason to use one of these approaches?
In Angular context.
You may have a component say MyComponent. There is a service as well for this component MyService. This service is responsible for some complex operation in MyComponent. Now you will make the subscription in the MyComponent as
$myObs.subscribe((val) => //do something );
But same data may be required in your service as well, so you define it in service as
$myObs.pipe(tap((val) => // do something with data in service));
Subscription will be done in component but using tap you can assign data member variable in your service as well.

Create code to clean up and add sample data to tables with relationship [duplicate]

I've been developing JavaScript for a few years and I don't understand the fuss about promises at all.
It seems like all I do is change:
api(function(result){
api2(function(result2){
api3(function(result3){
// do work
});
});
});
Which I could use a library like async for anyway, with something like:
api().then(function(result){
api2().then(function(result2){
api3().then(function(result3){
// do work
});
});
});
Which is more code and less readable. I didn't gain anything here, it's not suddenly magically 'flat' either. Not to mention having to convert things to promises.
So, what's the big fuss about promises here?
Promises are not callbacks. A promise represents the future result of an asynchronous operation. Of course, writing them the way you do, you get little benefit. But if you write them the way they are meant to be used, you can write asynchronous code in a way that resembles synchronous code and is much more easy to follow:
api().then(function(result){
return api2();
}).then(function(result2){
return api3();
}).then(function(result3){
// do work
});
Certainly, not much less code, but much more readable.
But this is not the end. Let's discover the true benefits: What if you wanted to check for any error in any of the steps? It would be hell to do it with callbacks, but with promises, is a piece of cake:
api().then(function(result){
return api2();
}).then(function(result2){
return api3();
}).then(function(result3){
// do work
}).catch(function(error) {
//handle any error that may occur before this point
});
Pretty much the same as a try { ... } catch block.
Even better:
api().then(function(result){
return api2();
}).then(function(result2){
return api3();
}).then(function(result3){
// do work
}).catch(function(error) {
//handle any error that may occur before this point
}).then(function() {
//do something whether there was an error or not
//like hiding an spinner if you were performing an AJAX request.
});
And even better: What if those 3 calls to api, api2, api3 could run simultaneously (e.g. if they were AJAX calls) but you needed to wait for the three? Without promises, you should have to create some sort of counter. With promises, using the ES6 notation, is another piece of cake and pretty neat:
Promise.all([api(), api2(), api3()]).then(function(result) {
//do work. result is an array contains the values of the three fulfilled promises.
}).catch(function(error) {
//handle the error. At least one of the promises rejected.
});
Hope you see Promises in a new light now.
Yes, Promises are asynchronous callbacks. They can't do anything that callbacks can't do, and you face the same problems with asynchrony as with plain callbacks.
However, Promises are more than just callbacks. They are a very mighty abstraction, allow cleaner and better, functional code with less error-prone boilerplate.
So what's the main idea?
Promises are objects representing the result of a single (asynchronous) computation. They resolve to that result only once. There's a few things what this means:
Promises implement an observer pattern:
You don't need to know the callbacks that will use the value before the task completes.
Instead of expecting callbacks as arguments to your functions, you can easily return a Promise object
The promise will store the value, and you can transparently add a callback whenever you want. It will be called when the result is available. "Transparency" implies that when you have a promise and add a callback to it, it doesn't make a difference to your code whether the result has arrived yet - the API and contracts are the same, simplifying caching/memoisation a lot.
You can add multiple callbacks easily
Promises are chainable (monadic, if you want):
If you need to transform the value that a promise represents, you map a transform function over the promise and get back a new promise that represents the transformed result. You cannot synchronously get the value to use it somehow, but you can easily lift the transformation in the promise context. No boilerplate callbacks.
If you want to chain two asynchronous tasks, you can use the .then() method. It will take a callback to be called with the first result, and returns a promise for the result of the promise that the callback returns.
Sounds complicated? Time for a code example.
var p1 = api1(); // returning a promise
var p3 = p1.then(function(api1Result) {
var p2 = api2(); // returning a promise
return p2; // The result of p2 …
}); // … becomes the result of p3
// So it does not make a difference whether you write
api1().then(function(api1Result) {
return api2().then(console.log)
})
// or the flattened version
api1().then(function(api1Result) {
return api2();
}).then(console.log)
Flattening does not come magically, but you can easily do it. For your heavily nested example, the (near) equivalent would be
api1().then(api2).then(api3).then(/* do-work-callback */);
If seeing the code of these methods helps understanding, here's a most basic promise lib in a few lines.
What's the big fuss about promises?
The Promise abstraction allows much better composability of functions. For example, next to then for chaining, the all function creates a promise for the combined result of multiple parallel-waiting promises.
Last but not least Promises come with integrated error handling. The result of the computation might be that either the promise is fulfilled with a value, or it is rejected with a reason. All the composition functions handle this automatically and propagate errors in promise chains, so that you don't need to care about it explicitly everywhere - in contrast to a plain-callback implementation. In the end, you can add a dedicated error callback for all occurred exceptions.
Not to mention having to convert things to promises.
That's quite trivial actually with good promise libraries, see How do I convert an existing callback API to promises?
In addition to the already established answers, with ES6 arrow functions Promises turn from a modestly shining small blue dwarf straight into a red giant. That is about to collapse into a supernova:
api().then(result => api2()).then(result2 => api3()).then(result3 => console.log(result3))
As oligofren pointed out, without arguments between api calls you don't need the anonymous wrapper functions at all:
api().then(api2).then(api3).then(r3 => console.log(r3))
And finally, if you want to reach a supermassive black hole level, Promises can be awaited:
async function callApis() {
let api1Result = await api();
let api2Result = await api2(api1Result);
let api3Result = await api3(api2Result);
return api3Result;
}
In addition to the awesome answers above, 2 more points may be added:
1. Semantic difference:
Promises may be already resolved upon creation. This means they guarantee conditions rather than events. If they are resolved already, the resolved function passed to it is still called.
Conversely, callbacks handle events. So, if the event you are interested in has happened before the callback has been registered, the callback is not called.
2. Inversion of control
Callbacks involve inversion of control. When you register a callback function with any API, the Javascript runtime stores the callback function and calls it from the event loop once it is ready to be run.
Refer The Javascript Event loop for an explanation.
With Promises, control resides with the calling program. The .then() method may be called at any time if we store the promise object.
In addition to the other answers, the ES2015 syntax blends seamlessly with promises, reducing even more boilerplate code:
// Sequentially:
api1()
.then(r1 => api2(r1))
.then(r2 => api3(r2))
.then(r3 => {
// Done
});
// Parallel:
Promise.all([
api1(),
api2(),
api3()
]).then(([r1, r2, r3]) => {
// Done
});
Promises are not callbacks, both are programming idioms that facilitate async programming. Using an async/await-style of programming using coroutines or generators that return promises could be considered a 3rd such idiom. A comparison of these idioms across different programming languages (including Javascript) is here: https://github.com/KjellSchubert/promise-future-task
No, Not at all.
Callbacks are simply Functions In JavaScript which are to be called and then executed after the execution of another function has finished. So how it happens?
Actually, In JavaScript, functions are itself considered as objects and hence as all other objects, even functions can be sent as arguments to other functions. The most common and generic use case one can think of is setTimeout() function in JavaScript.
Promises are nothing but a much more improvised approach of handling and structuring asynchronous code in comparison to doing the same with callbacks.
The Promise receives two Callbacks in constructor function: resolve and reject. These callbacks inside promises provide us with fine-grained control over error handling and success cases. The resolve callback is used when the execution of promise performed successfully and the reject callback is used to handle the error cases.
No promises are just wrapper on callbacks
example
You can use javascript native promises with node js
my cloud 9 code link : https://ide.c9.io/adx2803/native-promises-in-node
/**
* Created by dixit-lab on 20/6/16.
*/
var express = require('express');
var request = require('request'); //Simplified HTTP request client.
var app = express();
function promisify(url) {
return new Promise(function (resolve, reject) {
request.get(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
resolve(body);
}
else {
reject(error);
}
})
});
}
//get all the albums of a user who have posted post 100
app.get('/listAlbums', function (req, res) {
//get the post with post id 100
promisify('http://jsonplaceholder.typicode.com/posts/100').then(function (result) {
var obj = JSON.parse(result);
return promisify('http://jsonplaceholder.typicode.com/users/' + obj.userId + '/albums')
})
.catch(function (e) {
console.log(e);
})
.then(function (result) {
res.end(result);
}
)
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
//run webservice on browser : http://localhost:8081/listAlbums
JavaScript Promises actually use callback functions to determine what to do after a Promise has been resolved or rejected, therefore both are not fundamentally different. The main idea behind Promises is to take callbacks - especially nested callbacks where you want to perform a sort of actions, but it would be more readable.
Promises overview:
In JS we can wrap asynchronous operations (e.g database calls, AJAX calls) in promises. Usually we want to run some additional logic on the retrieved data. JS promises have handler functions which process the result of the asynchronous operations. The handler functions can even have other asynchronous operations within them which could rely on the value of the previous asynchronous operations.
A promise always has of the 3 following states:
pending: starting state of every promise, neither fulfilled nor rejected.
fulfilled: The operation completed successfully.
rejected: The operation failed.
A pending promise can be resolved/fullfilled or rejected with a value. Then the following handler methods which take callbacks as arguments are called:
Promise.prototype.then() : When the promise is resolved the callback argument of this function will be called.
Promise.prototype.catch() : When the promise is rejected the callback argument of this function will be called.
Although the above methods skill get callback arguments they are far superior than using
only callbacks here is an example that will clarify a lot:
Example
function createProm(resolveVal, rejectVal) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
console.log("Resolved");
resolve(resolveVal);
} else {
console.log("Rejected");
reject(rejectVal);
}
}, 1000);
});
}
createProm(1, 2)
.then((resVal) => {
console.log(resVal);
return resVal + 1;
})
.then((resVal) => {
console.log(resVal);
return resVal + 2;
})
.catch((rejectVal) => {
console.log(rejectVal);
return rejectVal + 1;
})
.then((resVal) => {
console.log(resVal);
})
.finally(() => {
console.log("Promise done");
});
The createProm function creates a promises which is resolved or rejected based on a random Nr after 1 second
If the promise is resolved the first then method is called and the resolved value is passed in as an argument of the callback
If the promise is rejected the first catch method is called and the rejected value is passed in as an argument
The catch and then methods return promises that's why we can chain them. They wrap any returned value in Promise.resolve and any thrown value (using the throw keyword) in Promise.reject. So any value returned is transformed into a promise and on this promise we can again call a handler function.
Promise chains give us more fine tuned control and better overview than nested callbacks. For example the catch method handles all the errors which have occurred before the catch handler.
Promises allows programmers to write simpler and far more readable code than by using callbacks.
In a program, there are steps want to do in series.
function f() {
step_a();
step_b();
step_c();
...
}
There's usually information carried between each step.
function f() {
const a = step_a( );
const b = step_b( a );
const c = step_c( b );
...
}
Some of these steps can take a (relatively) long time, so sometimes you want to do them in parallel with other things. One way to do that is using threads. Another is asynchronous programming. (Both approaches has pros and cons, which won't be discussed here.) Here, we're talking about asynchronous programming.
The simple way to achieve the above when using asynchronous programming would be to provide a callback which is called once a step is complete.
// step_* calls the provided function with the returned value once complete.
function f() {
step_a(
function( a )
step_b(
function( b )
step_c(
...
)
},
)
},
)
}
That's quite hard to read. Promises offer a way to flatten the code.
// step_* returns a promise.
function f() {
step_a()
.then( step_b )
.then( step_c )
...
}
The object returned is called a promise because it represents the future result (i.e. promised result) of the function (which could be a value or an exception).
As much as promises help, it's still a bit complicated to use promises. This is where async and await come in. In a function declared as async, await can be used in lieu of then.
// step_* returns a promise.
async function f()
const a = await step_a( );
const b = await step_b( a );
const c = await step_c( b );
...
}
This is undeniably much much more readable than using callbacks.

NodeJS wait for callback to finish on event emit

I have and application written in NodeJS with Express and am attempting to use EventEmitter to create a kind of plugin architecture with plugins hooking into the main code by listening to emitted events.
My problem comes when a plugin function makes an async request (to get data from mongo in this case) this causes the plugin code to finish and return control back to the original emitter which will then complete execution, before the async request in the plugin code finishes.
E.g:
Main App:
// We want to modify the request object in the plugin
self.emit('plugin-listener', request);
Plugin:
// Plugin function listening to 'plugin-listener', 'request' is an arg
console.log(request);
// Call to DB (async)
this.getFromMongo(some_data, function(response){
// this may not get called until the plugin function has finished!
}
My reason for avoiding a callback function back to the main code from the 'getFromMongo' function is that there may be 0 or many plugins listening to the event. Ideally I want some way to wait for the DB stuff to finish before returning control to the main app
Many Thanks
Using the EventEmitter for plugin/middleware management is not ideal, because you cannot ensure that the listeners are executed sequentially, if they have asynchroneous code. This especially is a problem when these listeners interact with each other or the same data.
That's why i.e. connect/express middleware functions are stored in an array and executed one after the other, instead of using an EventEmitter; They each need to call a next(); function when they are done doing their task.
You can't mix asynchronous calls with synchronous behavior. If you're going to stick with event emitter (which may not be ideal for you as Klovadis pointed out), you'll need to have your plugin emit an event that triggers a function in the main app which contains the code that you want to 'wait' to execute. You would also have to in turn keep track of all the plugin calls you made that you are waiting for event calls for so that your main code doesn't run until all the plugin calls have finished their MongoDB callbacks.
var callList = ['pluginArgs1', 'pluginArgs2', 'pluginArgs3'];
for (var i = 0; i < callList.length; i++){
self.emit('plugin-listener', callList[i], i);
}
self.on('plugin-callback', function(i){
callList.splice(i, 1);
if (callList.length < 1){
//we're done, do something
}
});
Had the same kind of decision to make about some events that I sometime need to wait for before returning the response to the client and sometimes not (when not in an HTTP request context).
The easiest way for me was to add a callback as the last argument of the event.
Stuff.emit('do_some_stuff', data, data2, callback);
In the event check if there is a callback:
Stuff.on('do_some_stuff', function(data, data2, callback) {
// stuff to do
// ...
if (typeof callback === "function") return callback(err, result);
});
I know that mixing event and callbacks can be messy but that work fine for what I need.
The other solution I see is the one proposed by #redben: add an emit function at the end of the event. The problem when in a HTTP context is that you need unique keys so your events don't mess up if they do different stuff per user.
Haven't tried it myself but you could use a property in the event's data object as an array of functions to execute by the code that emitted the event :
Listeners
foo.on('your-event', function(data) {
console.log(data);
// Then add the asynchronous code to a callbacks array
// in the event data object
data.callbacks.push(function(next) {
getFromMongo(some_data, function(err, result) { next(err) }
}
});
Emitter
self.emit('your-event', data);
// listeners have modified data object,
// some might have added callback to data.callbacks
// (suppose you use async)
async.series(data.callbacks);
This seems quite dangerous, but I have to do it anyway...
const ee = new EventEmitter();
if (ee.listeners("async-event").length > 0) {
await new Promise((resolve) => {
ee.emit("async-event", data1, data2, resolve);
});
}
Otherwise, just emit the event back-and-forth.

How to create custom event listener in node.js (express.js)?

I have a giant function with a lot of nested callbacks. I want to make it cleaner and easier to handle. So, I'm thinking of using custom event listeners
Like, when a function is done, in the callback, instead of putting a chunk of code, it just emits an event, and then the listener will run.
So, how to do that in node.js? I am still looking for a good example to guide me through.
You can set events like this
app.on('event:user_created', callback);
Then you can emit them
app.emit('event:user_created', data);
express.js uses EventEmitter.
You probably want to create an EventEmitter object, and call emit() on it.
I just came across this question, I'd like to chip in my 2 cents, specifically responding to Luis.
In Express, if you want the 'app' instance to listen for a custom event you would do something like:
app.on('testEvent', function () {
return console.log('responded to testEvent');
});
app.get('/test', function (req, res) {
app.emit('testEvent');
return res.status(200).end();
});
Then when that route is hit, you'd see the response in the console. Of course you can implement this as you wish.
The Node.js "events" module and the "EventEmitter" module facilitates communication between objects in Node. The EventEmitter module is at the core of Node's asynchronous event-driven architecture. Here is how you can create custom events and emit them:
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
//Event Listener
const EventListenerFunc = () => {
console.log('an event occurred!');
}
//Registering the event with the listener
myEmitter.on('eventName', EventListenerFunc);
//Emitting the event
myEmitter.emit('eventName');

Resources