I have two requests and some function to be called in between. The flow is that when the first promise is called and finished, no matter what result is (success or failure) some non-promise related function should be called and only after we should call the second promise. So this is how I ended up doing it, which does not look like a good solution.
funtionReturnsPromise()
.then(()=>{})
.catch(()=>{})
.then(()=>{
nonPromiseRelatedFuntion()
})
.then(()=>{
return funtionReturnsPromise2()
})
Since the desired flow is:
Promise > Function > Promise
On which the function is executed no matter the outcome of the first promise, you can simply do something like:
function secondFunction(outcome) {
// do stuff
return funtionReturnsPromise2()
}
functionReturnsPromise().then(secondFunction).catch(secondFunction)
Now, on another topic, I would not call the second function 'unrelated' since it clearly, according to your explanation, needs to be called after the first promise is fulfilled.
Assuming nonPromiseRelatedFuntion is sync and you're not interested in return value of functionReturnsPromise
functionReturnsPromise()
.then(
// no matter what happens, the function is invoked
() => { nonPromiseRelatedFunction() },
error => {
nonPromiseRelatedFunction()
// do error handling from functionReturnsPromise
}
)
.then(() => functionReturnsPromise2() }
.catch(console.error)
If you need a value:
functionReturnsPromise()
.then(
value => {
nonPromiseRelatedFunction()
return functionReturnsPromise2(value)
},
error => {
nonPromiseRelatedFunction()
// do error handling from functionReturnsPromise
}
)
.catch(console.error) // error handling from functionReturnsPromise2
Like the other answers I'm assuming
nonPromiseRelatedFunction is synchronous
you really don't care about any return values
nonPromiseRelatedFunction and funtionReturnsPromise2 should be executed in all circumstances
Having read ALL the comments to the question, I see the above is not an assumption after all
The simplest solution is to get rid of the first .then
funtionReturnsPromise()
.catch(()=>{})
.then(()=>{
nonPromiseRelatedFuntion()
})
.then(()=>{
return funtionReturnsPromise2()
})
Note: such code could be written
funtionReturnsPromise()
.catch(()=>{})
.then(nonPromiseRelatedFuntion)
.then(funtionReturnsPromise2)
sure, the last two functions will receive arguments, but if the code in those functions ignores arguments anyway, then their will be no issue
Related
I am currently learning javascript and i find this often on tuitorials i watch. Javascript automatically pass the result of a function as a parameter to the next function.
fetch('SampleApi')
.then( function(data) { return data.json() } )
.then( function(data) { console.log(data.name); } )
.catch(function(err) { console.log(error) })
the result of the fetch goes directly as a parameter to the function then the result of the function goes directly as a parameter to the next function.
I just want to know what is this and what is this called. I need to understand this before diving deep.
EDIT: modified example to show passing parameters between methods to directly answer the qeustion.
The underlying premise is that JavaScript can act upon a returned result immediately as long as the operation requested is sane and available. A simple example is shown here:
console.log("|" + " This is a string with extra spaces ".trim() + "|");
This can be accomplished in your own code as well. In the following example, note the return of the operation is the object itself. This allows us to carry out any operation available within that object upon the return from some other operation in the same object:
class Test {
sayHi(message = "Passed Message") {
console.log('parameter: ' + message);
this.message = message;
return this;
}
sayBye(cb) {
cb(this.message);
return this;
}
}
const test = new Test();
test.sayHi("hello!").sayBye(passed => console.log('passed in: ' + passed));
So throughout your experience with JavaScript you will find many instances of this idea that is called method chaining.
In the example you provided, it is simply this concept applied to the fetch API.
It's called function chaining.
The fetch function returns an object that has a function then, which accepts a function as its parameter.
When then is called, it executes the given function with the data stored within the object as a parameter, and stores the return value as the new internal data, which is passed to the function in the second then call. then returns the same object that was returned from fetch.
The call to catch will check if an error was encountered (and stored into the object), and if so, will call the given function with the error.
You could spread out the whole thing, without chaining:
var o = fetch('SampleApi');
o = o.then(function(data) { return data.json(); });
o = o.then(function(data) { console.log(data.name); });
o.catch(function(error) { console.log(error); });
The short answer is "That's just how promises work"
To better illustrate WHY this is good behavior:
function getOrganizedData() {
return fetch("somedata").then(function(rawData) {
// do some stuff
return organizedData;
});
}
Anyone using this function will be able to use the organizedData - so if you have a shared service, only that service needs to know how to translate rawData into organizedData for the rest of the application to use.
What if that's not the behavior you want?
Easy, just don't chain the promises:
const fetchPromise = fetch('SampleApi');
fetchPromise.then( function(data) { return data.json() } );
fetchPromise.then( function(data) { console.log(data.name); } );
fetchPromise.catch(function(err) { console.log(error) });
But wait, won't I get errors with that approach because the catch isn't applied to each chain?
Yes! So, you need to catch BOTH chains:
const errorFunction = function(err) { console.log(error) };
const fetchPromise = fetch('SampleApi');
fetchPromise.then( function(data) { return data.json() } ).catch(errorFunction);
fetchPromise.then( function(data) { console.log(data.name); } ).catch(errorFunction);
NOTE: This chaining behavior applies to .catch as well:
fetch("somethingThatWillError")
.then(function() { console.log("THEN - I will not run because there's an error"); })
.catch(function() { console.log("CATCH - I will run because I am handling the error"); })
.then(function() { console.log("THEN - I will run because the error has been handled"); })
.catch(function() { console.log("CATCH - I will not run because there is no error to handle"); })
Edit : For resume, the result of fetch is the first data in case of success, the second data is the return of the first then and err the result of fetch in case of reject.
You are actually playing with promise here, you can look some documentation about Promise here.
In javascript your running task can be synchronous or asynchronous, promise is for handling asynchronous task. You can know more about asynchronous here.
To be quick and simple a promise can be resolve now, in ten minutes or never. When you are building a Promise, you need an executor which is passed with two arguments, a resolve function and a reject function, they will be call just before the final resolution of your promise, (after an API call for exemple).
The reject gonna be call if your promise fail (timed out on your api call for example) and the resolve gonna be call on the success of your promise. In this two callbacks (resolve and promise), if you don't know about callback you have to learn it here, you will have an argument with the return of the resolution of your promise, for example if the promise is rejected you gonna have the reason in a message and in the resolve you gonna have the data that you need from your api call.
In your case, the fetch is build like fetch = new Promise(...); where then(...) is the success resolver and catch(...) the rejected resolver. You can have a finally(...) which is called after the then() and catch().
And the data in your example is the result of your promise if it's a success and err is the result in case of error result.
I met an article about promises in js, where the author shows a piece of code:
// I want to remove() all docs
db.allDocs({include_docs: true}).then(function (result) {
result.rows.forEach(function (row) {
db.remove(row.doc);
});
}).then(function () {
// I naively believe all docs have been removed() now!
});
and says
What's the problem with this code? The problem is that the first
function is actually returning undefined, meaning that the second
function isn't waiting for db.remove() to be called on all the
documents. In fact, it isn't waiting on anything, and can execute when
any number of docs have been removed!
So, as I understood, if the second callback function() {} accepts no arguments, it actually doesn't wait for the end of the callback function(result). Am I inferring correctly? Because when I run the following piece of code, it gives me an opposite result:
var array = [];
for ( let i = 0; i < 1000; i++ )
array.push(i);
var promise = new Promise((resolve, reject) => {
setTimeout(() => resolve(), 1000);
});
promise
.then(() => array.forEach(item => console.log(item)))
.then(() => console.log("invoked earlier"));
I wait for "invoked earlier" to appear in the middle of printed numbers. But doesn't matter how large the number of items is. "Invoked earlier" appears always at the end. Can someone explain me what I am missing? Maybe the article is outdated and something has changed since then?
In order to guarantee this, you actually have to return promises from the previous promise.
Whatever you return from a promise will be passed into the next promise.
In your case, you're returning undefined.
If, instead, you returned a promise, then the promise would be resolved, and the second promise would run after that happened, and would be passed whatever value the promise resolved with.
So yes, promises are guaranteed to run one after another, but if you choose to do something async inside of their callback, and don't bother chaining it back into the promise by returning it, then they're not going to bother to wait for anything (because they don't know that there's anything to wait for).
I'm assuming db.remove returns a promise...
...so, knowing that we have to return a promise from the callback, in order for it to actually wait for async stuff to happen, I would do something like this.
.then(result => Promise.all(result.rows.map(row => db.remove(row.doc))))
.then((listOfRemoves) => console.log(`removed`));
Whether the second function takes 1 argument or 0 arguments is 100% inconsequential as to when the second function runs.
Edit
examples:
.then(() => setTimeout(() => console.log('2nd', 20000)))
.then(() => console.log('first'));
This happens because the first then has NO idea that there is a setTimeout happening. It's not a mind-reader, it just runs the code and passes the return value along (in this case, undefined).
If the return value happens to be a promise, though, it will wait until that promise is done, get the value from it, and pass that on.
.then(() => new Promise(resolve => setTimeout(resolve, 20000)))
.then(() => console.log('I waited 20 seconds.'));
Because it's returning a promise, it will call the then of that promise, and wait to get the value, to pass on.
The reason your tests are failing is because you're basically doing this.
.then(() => console.log('first'))
.then(() => console.log('second'));
These are guaranteed to fire in this order. Period.
All of the other ones have been firing in that order as well. It's just that they are also scheduling async processes, just like all other callbacks/timeouts that use async I/O in JS.
The following code contains two kinds of promise chain, seems they'r equivalent, but I don't understand why they are equivalent. I think of it like 2*(3+4) = 2*3+4, which is not correct.
// example1
runAsync1()
.then(function(data1){
return runAsync2()
.then(function(data2){
return runAsync3();
})
})
.then(function(data3){
console.log(data3);
});
// example 2
runAsync1()
.then(function(data1){
return runAsync2();
}).then(function(data2){
return runAsync3();
}).then(function(data3){
console.log(data3);
});
Maybe some braces would help you understand this a little better. (NOTE: this is exactly the same thing as you had except with an extra set of braces on the return)
// example1
runAsync1()
.then(function(data1){
return (
runAsync2()
.then(function(data2){
return runAsync3();
})
)
})
.then(function(data3){
console.log(data3);
});
So what is happening here,
.then is called on runAsynch1()
.then is then called on runAsynch2() which returns runAsynch3() (this return carries on all the way down the chain of returns)
finally .then is called on the returned runAsynch3()
As you can see, this is exactly the same process as what happens in example 2
// example 2
runAsync1()
.then(function(data1){
return runAsync2();
}).then(function(data2){
return runAsync3();
}).then(function(data3){
console.log(data3);
});
It's a little bit implementation-specific, but the magic, regardless of the specifics is in the then.
Then does a couple of things.
The TL;DR is that then subscribes to returned promise chains, but below are examples closer to the guts of a promise.
The first thing is:
"Is the promise still pending? Then schedule these callbacks for later; otherwise, schedule this callback to run on the next tick (setTimeout(handle, 0)). Return a new promise that resolves/rejects to the eventual value."
// basically accurate-ish
then (onSuccess, onError) {
return new Promise((resolveNext, rejectNext) => {
if (myPromiseIsDone) {
// I already have the value; run the next step ASAP
// this is ugly, but hopefully it proves a point
runOnNextTick(onSuccess, onError, promiseResult, resolveNext, rejectNext);
} else {
// I don't have a result yet; come back when it's ready
scheduleWhenDone(onSuccess, onError, resolveNext, rejectNext);
}
});
}
The second is where your answer lies:
"Run the handler. Get the return value from the callback passed to then. Is the return value a Thenable object (has a then method)? Then call then and pass in the resolve/reject functions that control my promise... otherwise, resolve/reject accordingly, based on whether it throws or returns."
// entirely subjective and implementation-specific,
// but the algorithm is almost spec-compliant
handleSuccess (onSuccess, resolveNext, rejectNext, value) {
if (!onSuccess) {
// if they didn't give me a `then(callback)`,
// just pass the value to the next promise
resolveNext(value);
return;
}
try {
// I'm running the `then(callback)` here
const result = onSuccess(value);
if (hasThenMethod(result)) {
// it's promise-like, subscribe
result.then(resolveNext, rejectNext);
} else {
resolveNext(result);
}
} catch (err) {
// something blew up, while trying to succeed, so fail
rejectNext(err);
}
}
Reject looks similar.
So the outer then subscribes to the inner then.
If you ever wanted to get into functional programming, the ES6 Promise is almost a monad.
The difference is that a monad would force you to have a different method, to tell it to chain to the returned promise, rather than doing it automatically.
then is basically the same as map on arrays. You call then, pass it a function that gets the value and returns a new promise with the transformed value.
So a monadic promise might be one that has map and chain, or then and chain, where chain does almost exactly the same thing but says "hey, then, this callback is going to return a promise; subscribe to that one, so that you flatten it out, rather than returning a promise of a promise of a value".
That's almost all it would take to be a monad.
Hope that all helps.
According to my code below i am chaining all the data until the end where i wish to render the data to the view however using the .catch i found that summoner is not accessible at the final function.
getSummonerData(req.params.playerName)
.then(function(summoner) {
return getMatchIds(summoner[0].id);
})
.then(function(matchIds) {
return getGameData(matchIds);
})
.then(function(gameData) {
res.render('profile', {player:summoner, games:gameData});
})
.catch(function(e) {
console.log(e);
});
In your code, summoner is only accessible to the then callback containing your call to getMatchIds, not elsewhere. To be accessible later, you'd have to either 1) Return it from that then callback along with the game data, or 2) Nest the then callbacks that need it inside that callback.
The latter is probably the easier one:
getSummonerData(req.params.playerName)
.then(function(summoner) {
return getMatchIds(summoner[0].id)
.then(function(matchIds) {
return getGameData(matchIds);
})
.then(function(gameData) {
res.render('profile', {player:summoner, games:gameData});
});
})
.catch(function(e) {
console.log(e);
});
I am not sure what you mean by "promise function". I am guessing you are not aware that 'then' and 'catch' always return promises. That is why you can chain them. Each 'then' or 'catch' is a method of the promise returned by its predecessor. Those chained promises are later resolved or rejected depending on what happens to their predecessors.
I assume your last function 'res.render(...)' returns the value you want to see. Then the promise 'then(render(...))' will become resolved with the value received from 'res.render(...)'.
So that is what 'catch' will be working with: a resolved promise with the value you want to see. But 'catch' only fires its function with a 'rejected' promise. You need a 'then' instead.
My Promise issue
I am new to Promises and I've been reading the Q Documentation, where it says:
When you get to the end of a chain of promises, you should either return the last promise or end the chain.
I have defined a Promise in my code the Q.Promise way, with the following console.logs to log out an execution trace:
function foo(){
return Q.Promise(function(resolve, reject) {
doSomething()
.then(function() {
console.log('1');
return doSomething1();
})
.then(function() {
console.log('2');
return doSomething2();
})
.then(function() {
console.log('3');
return doSomething3();
})
.catch(function(err) {
console.log('catch!!');
reject(err);
})
.done(function() {
console.log('done!!');
resolve();
});
});
}
In case every doSomethingN() executes correctly, everything works as intended and I get the expected trace:
1
2
3
done!!
But in case any of the doSomethingN() fails:
foo() works correctly, because the error function callback is the one that runs whenever a reject(err) occurs:
foo().then(function() { /* */ }, function(err) { /* this runs! */ });
And I get the following trace (ie. when doSomething1() fails):
1
catch!!
done!!
My question
What I thought at first was the following:
Okay, let's handle the chaining success and failure in both: .done() and .catch() methods. If everything goes well .done()'s callback will be executed and the promise will be resolved. In case there's an error at any point, .catch()'s callback will be executed and the promise will be rejected - and because of that, done() won't be executed.
I think I am missing something about how the .done() works... because by having a look at my logging trace, I realized that .done() seems to be executing always - whether there is an error and .catch() is executed or not - and that is what I wasn't expecting.
So, after that, I removed .done()'s callback and now foo():
works if there's an error during the chain execution
does not work if everything works correctly
What should I reconsider and how could/should I make it work?
catch(cb) is just an alias for then(null, cb), and you've actually fixed an error in catch, so flow naturally turned to success result in done.
If you want to just decorate the error in catch, you should rethrow the error afterwards, e.g. proper passthru may look as:
catch(function (err) {
console.log(err);
throw err;
});
Still your example doesn't make much sense. You should never use done, when you return a promise. If you want to resolve initialized promise with internally created chain of promises, you should just resolve it as:
resolve(doSomething()
.then(function() {
console.log('1');
return doSomething1();
})
....
.then(function() {
console.log('N');
return doSomethingN();
}));
There's no need for internal error handling, leave that to consumer of promise which you return.
And other point. If when creating new promise you know it will be resolved with other one, then there's no logical reason to create such promise, just reuse one you planned to resolve with. Such error was also coined as deferred anti-pattern
You should consider doing this:
function foo() {
// Calling .then() on a promise still return a promise.
// You don't need Q.Promise here
return doSomething()
.then(function(doSomethingResult) {
console.log('1');
return doSomething1();
})
.then(function(doSomething1Result) {
console.log('2');
return doSomething2();
})
.then(function(doSomething2Result) {
console.log('3');
return doSomething3();
});
}
foo()
.then(function(fooResult) {
console.log(fooResult); // fooResult should be what is returned by doSomething3()
})
.catch(function(err) {
console.error(err); // Can be thrown by any
})
.done(function() {
console.log('I am always executed! error or success');
});
If you want to return a promise, in most cases it does not make much sense to use catch (unless you want to recover potential errors). It never make sense to use done in a method returning a promise. You would rather use these methods at the very end of the chain.
Notice that doSomethingX() can return either a value, or a promise, it will work the same.
You can make it work by resolving promise in your last then callback.
function foo(){
return doSomething()
.then(function() {
console.log('1');
return doSomething1();
})
.then(function() {
console.log('2');
return doSomething2();
})
.then(function() {
console.log('3');
return doSomething3();
})
}
Consider using bluebird for promises. It has many useful features as compared to any other promise library. You may find it difficult to begin it, but once you get hold of it you're going to love it.