I have some hard time understanding what is the difference between using Promise.resolve() and simple using the promise.
The explanation seems a bit hard to get so i have a little example:
For example, i have a method that return a promise like this:
requestPokemon() {
return new Promise((resolve, reject) => {
axios.get("https://pokeapi.co/api/v2/pokemon/1").then(value => {
resolve(value);
})
.catch(error => {
reject(error);
})
});
}
so, now i can call this method and chain the promise, i figure two ways of do it, and can't get it when Promise.resolve is better or not, my issue is understanding that.
so i solved it in two ways:
first:
Promise.resolve(this.requestPokemon()).then(value => {
this.pokemon = value.data.name;
}).catch(error => {
console.log(error);
})
second:
this.requestPokemon().then(value => {
this.pokemon = value.data.name;
}).catch(error => {
console.log(error);
})
please i need a little explanation of the downsides and upsides on doing it one way above the other, i appreciate the help a lot.
Thanks
At first you dont need to construct a promise (thats an antipattern) in your requestPromise, just return the one from axios:
requestPokemon() {
return axios.get("https://pokeapi.co/api/v2/pokemon/1");
}
Now lets have a look at this line:
Promise.resolve(this.requestPokemon()).then(/*...*/)
It will create a new promise, that resolves or rejects when the axios promise resolves or rejects and adds a then handler to it. So it will be chained like this like this:
resolve() -> Promise (axios) -> Promise (Promise.resolve) -> then
reject() -> Promise (axios) -> Promise (Promise.resolve) -> catch
So as you can see Promise.resolve just passes through the data, so actually it is superflous. We actually just need:
resolve() -> Promise (axios) -> then
reject() -> Promise (axios) -> catch
Which can be done with:
this.requestPokemon().then(/*...*/, /*...*/);
please i need a little explanation of the downsides and upsides on doing it one way above the other
Adding Promise.resolve is just a bit more typing and makes it less readable, there is no syntactical difference.
Related
How do you handle promises that do not resolve?
Example:
class Utils {
static async thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(number: number) {
return new Promise((resolve, reject) => {
if(number === 2) {
resolve('ok')
}
})
}
}
console.log(await Utils.thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(2))
// this will print "ok" because 2 is passed and the promise is resolved
console.log(await Utils.thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(5))
// this will crash the program silently
uncaughtException and unhandledRejection return nothing when the promise is unresolved. Adding a try/catch around the await doesn't work (no errors). Finally, the only thing that works is using Promise.then instead of await.
Problem is the code base is riddled with async/await and Promises that sometimes resolve (depending on conditions)
Question: Is there a typescript flag I can add to detect a missing resolve/reject? or maybe an automated way to transpile all the async/await to use Promise.then?
When using a debugger, the program stops after the Promise and it is difficult to find which function/promise has a missing resolve/reject.
Rewriting all the async/await calls to use Promise.then is my last resort.
If you have promises that occasionally don't resolve or reject and that's not the way they are supposed to work (which it usually isn't), then you just have to fix that. There really is no work-around. The proper fix is to get down to the lowest level and fix the code so it reliably resolves or rejects every time.
This is not the proper fix, but implementing a timeout wrapper could help with debugging giving you a log message with some semblance of a stack trace for a timed out promise:
function rejectT(t) {
// create potential error here for better opportunity at stack trace
let e = new Error("Promise timed out");
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(e);
reject(e);
}, t);
});
}
function timeout(p, t = 5000) {
return Promise.race([p, rejectT(t)]);
}
You can then wrap any promise such that instead of:
fn().then(...).catch(...)
You can use:
timeout(fn()).then(...).catch(...);
Or, if you want to set a custom timeout value:
timeout(fn(), 1000).then(...).catch(...);
Again, this is debugging code to help find the culprits that need fixing and to help test fixes, not to bandaid your code.
Rewriting all the async/await calls to use Promise.then is my last resort.
I don't see how this is going to help at all. If await never finishes, neither will promise.then(). They are exactly the same in that regard. If the promise never resolves or rejects, then the .then() handler will never get called either.
Problem is the code base is riddled with async/await and Promises that sometimes resolve (depending on conditions)
There's no shortcut here other than methodical code review to find suspect code that has code paths that may never resolve or reject and then building unit tests to test every function that returns a promise in a variety of conditions.
One likely source of code that never resolves or rejects are some of the promise anti-patterns. The precise reason some of them are anti-patterns is because they can be very easy to mess up. Here are a few references that might spike your sensitivity to suspect code:
Promise Anti-Patterns
Common Promise Anti-Patterns and How to Avoid Them
ES6 Promises: Patterns and Anti-Patterns
async function thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(number) {
return new Promise((resolve, reject) => {
if (number === 2) {
resolve('ok')
} else {
reject('error:' + number)
}
})
}
(async() => {
try {
console.log(await thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(2))
// this will print "ok" because 2 is passed and the promise is resolved
} catch (e) {
console.error(e);
}
try {
console.log(await thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(5))
// this will crash the program silently
} catch (e) {
console.error(e);
}
})()
I don’t understand why this piece of code results in such an order? Could anyone elaborate on this? I thought Promises were like a FIFO queue, but the nested Promise functions seems a little bit unpredictable, or maybe using some other data structure?
new Promise(resolve => {
resolve()
})
.then(() => {
new Promise(resolve => {
resolve()
})
.then(() => {
console.log(1)
})
.then(() => {
console.log(2)
})
.then(() => {
console.log(3.1)
})
})
.then(() => {
console.log(1.1)
new Promise((resolve => {
resolve()
}))
.then(() => {
new Promise(resolve => {
resolve()
})
.then(() => {
console.log(4)
})
.then(() => {
console.log(6)
})
}).then(() => {
console.log(5)
})
}).then(() => {
console.log(3)
})
console.log(0)
Output:
0
1
1.1
2
3
3.1
4
5
6
Promises are async. This means everytime you create a new promise- a new async operation starts.
What is async operation in JS? First you need to understand that JS operates on a single thread no matter what you do. So, to make it looks like its asynchronous- there is something called the "event loop" (took the link from comment to original post, tnx #Taki for the great source).
In general, the event loop stores all the async functions and "slips" in the actions between the main code actions. This is really over-simplified explanation, refer to the link to read more, but thats the gist of it.
So basically, there is no "FIFO" queue here- the async functions order is literally depends on stuff like your processor speed, your operating system, etc.
BUT- there is a way to make sure one async action does get performed only after another one finishes, and this is the .then clause. The thing is, it only assures the specific function inside the .then will be performed after the specific promise it was concatenated to, but it does not say anything about the order of it in regars to other async operations (promises) in the event loop. So for example in your code:
new Promise(resolve => {
resolve() // PROMISE A
})
.then(() => {
new Promise(resolve => {
resolve() // PROMISE B
})
.then(() => {
console.log(1) //PROMISE C
})
.then(() => {
console.log(2)
})
.then(() => {
console.log(3.1)
})
})
.then(() => {
console.log(1.1) // PROMISE D
new Promise((resolve => {
resolve()
}))
I took part of it to explain:
so, Promise A resolves first. this assures that promise B will resolve now. here is when things gets complicated: since promise B is resolved, both promise C and D now get into event loop! why? because Promise A had 2 .then clauses, so when the first one ends- event loop takes the 2nd one which is promise D. but the first .then clause had also a .then clause of his own - promise C, which also enters the event loop.
THERE IS NO CONNECTION BETWEEN PROMISE D AND C! They could be performed in any order. keep that logic and you'll see how it works out for the rest of the promises, and also if you try to run it on different OS it might be that promises order will be different because of different implementations of the OS for the event loop.
Hope this helps you to understand a little.
DISCLAIMER: I have not much experience in JS, but promises really intrigued me so I did a deep research about it. I'm standing behind everything I wrote here, but if there are any corrections to my explanation I'd love to hear!
EDIT
The answer beneath me is also correct but with no explanation, so let me add to it:
When you do not return anything inside a promise (or a .then clause, which also returns a promise), it will implicitly return a resolved promise with no value before going out of the promise, basically like adding a return new Promise.resolve() after teh console.log in promise C, for example. When its done like this, all the .then clauses coming after promise B will only enter the event loop after the previous one ended (e.g b ends, so C goes into loop, then the next .then and so on), but between them other promises or .then clauses (like promise D) can enter as well.
But, when you RETURN the promise that has the .then clauses chained to it- it makes sure the whole block of the promise + then clauses goes into event loop as one in order, so the .then clauses will also be performed in the order you wanted :)
tnx #Eugene Sunic for the addition!
It results in unpredictable order because of un-existing returns in your code.
Adding return to your promises and you'll get comprehensible outputs and can easily track the promises execution.
Firstly, synchronous 0 is printed then the entire first promise block gets executed, like you said FIFO.
1,2, 3.1
After that the chaining thenable gets executed
1.1
After that the block 4,6 gets printed
following the chaining thenable which outputs 5 and at last, the last thenable prints number 3
Leaving us with 0,1,2, 3.1, 1.1, 4,6,5,3
new Promise(resolve => resolve())
.then(() => {
return new Promise(resolve => resolve())
.then(() => console.log(1))
.then(() => console.log(2))
.then(() => console.log(3.1));
})
.then(() => {
console.log(1.1);
return new Promise((resolve => resolve()))
.then(() => {
return new Promise((resolve) => resolve())
.then(() => console.log(4))
.then(() => console.log(6))
}).then(() => console.log(5))
}).then(() => console.log(3))
console.log(0)
It's FIFO and the execution looks like this:
main [4] logs: 0 // main code executed, one executor added to FIFO (4)
4 [8,18] // executor at line 4 runs, two executors added to FIFO (8, 18)
8 [18,11] logs: 1 // etc etc
18 [11,23,36] logs: 1.1
11 [23,36,14] logs: 2
23 [36,14,27,33]
36 [14,27,33] logs: 3
14 [27,33] logs: 3.1
27 [33,30] logs: 4
33 [30] logs: 5
30 logs: 6
as you can see its first in first out order: [4,8,18,11,23,36,14,27,33,30] but it stores executors (callbacks for promises that were fulfilled or rejected), not promises. In other words: the time when promise is fulfilled or rejected decides when its added to FIFO not the time the promise is created.
Background
I started working at a company that doesn't have many patterns and I see the return of fetch calls in two ways. One returning just the fetch call and another returning a fetch call wrapped by Promise using resolve and reject, and this made me get confused.
Question
Is doing this
const returnFetchWrappedByPromise = () => {
return new Promise((resolve, reject) => {
return fetch("url")
.then(resolve(true))
.catch(reject(false))
})
}
The same as this
const returnFetch = () => {
return fetch("url")
.then(() => true)
.catch(() => false)
}
?
If not, what is the difference?
If yes, which one should I use?
Observation: I used true and false just to make an example, but in reality, is some result and some error.
The new Promise object within the returnFetchWrappedByPromise function is not needed. fetch already returns a Promise object (Screenshot below). You should use the returnFetch function. Hope that helps.
fetch inherently returns a promise, so wrapping it in a new Promise doesn't add any functionality. The use of async also does not add anything in this case and actually presents a case of the Promise constructor anti-pattern.
The second function syntax is the preferred way.
Reading the docs as I understand it in ES6 the meaning of:
foo => someFun(foo);
is equivalent to:
foo => { return someFun(foo); }
I'm returning a new Promise and within that code using arrow functions to invoke the resolve & reject methods, e.g.
return new Promise(function(resolve, reject)
{
someFunThatReturnsAPromise()
.then(data => resolve(data))
.catch(err => reject(err));
});
As such is the code in the then actually,
.then(data => return resolve(data))
If so, does it matter that the result of resolve (of which I'm not sure of the type of value) and should I instead be slightly less terse and write it using {} to prevent the implicit return
.then(data => { resolve(data); })
The resolve function already returns undefined, so it makes absolutely no difference if you implicitly return it with a one-line arrow function or don't return it from a function body at all (since the latter means your function body implicitly returns undefined itself).
Furthermore, since you've wrapped the promise returned by someFunThatReturnsAPromise() in a new promise, there's nothing that handles the return anyway so it wouldn't make any difference even if did return something.
More importantly, the way you've wrapped a promise in a new promise is an anti-pattern. The new Promise() construct is only for dealing with asynchronous processes that aren't already promise based.
Since someFunThatReturnsAPromise() already return a promise, you don't need to wrap it in a new one, simply use the one you got!
For your example that would simply mean returning it:
return someFunThatReturnsAPromise()
If you want to do some processing of the data, such as only returning a part of the data (the status property in the below example), you do that in a then callback:
return someFunThatReturnsAPromise().then(data => data.status)
When you return in a then callback, it will in turn return a new promise that gets resolved with the data you returned (unless you returned another promise, in which case it will resolve when that promise resolves).
This is how promises are designed to work, by chaining the asynchronous processes and their results.
If you just want to return data, and reject incase of an error then you don't need a then()
return new Promise(function(resolve, reject)
{
someFunThatReturnsAPromise()
.then(data => resolve(data))
.catch(err => reject(err));
});
would be equivalent to
return someFunThatReturnsAPromise()
unless you want to do some processing on data
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