I am a beginner to the weird ways Javascript works, and I am unable to understand the single threaded design and how Promises work.
Take the following code:
function a() {
return new Promise((resolve, reject) => {
var inn = new Promise((resolve, reject) => {
setTimeout(() => reject('Error'), 0);
}).catch((msg) => console.log(msg));
return inn;
});
}
a().then((msg) => console.log('then'));
My questions are the following:
The inner promise fails thats why I get Error printed, but why doesn't the other Promise resolve and get 'then' printed?
Does returning a Promise from a Promise means that the outer promise resolves ?
When I encounter a catch block does it mean the Promise is cancelled ?
Sorry if this is noob but I am unable to exactly find the answers that I looking for, most other posts are just confusing me.
Using new Promise within another new Promise is an antipattern, and what you experience here is a reason why.
You don't call any of the resolve and reject of the outer new Promise. The return inn has no effect, because the outer new Promise is only resolved or rejected, by either calling resolve, reject or by an error that is thrown, and neither of this is happening there.
That's how it should look like:
function a() {
return new Promise((resolve, reject) => {
setTimeout(() => reject('Error'), 0);
}).catch((msg) => console.log(msg));
}
a().then((msg) => console.log('then'));
You only use new Promise if you need to convert something async that does not provide a Promise as a result, into a Promise. And you want to keep the code footprint within that new Promise as small as possible, so that you can be sure that every code path will lead to either a resolve ar reject condition.
So turning a setTimeout into a Promise by wrapping it into a new Promise is fine. But at that point, you have a Promise, so there is no need to wrap that into another new Promise. That breaks the whole purpose of chaining and the guarantees Promises make. (What is the explicit promise construction antipattern and how do I avoid it?)
And you should not use strings as errors. Neither for throw nor for reject use reject(new Error('Error')) (or a custom error object) instead.
You must resolve inn within function a rather than return it in order for the promise chain to continue unbroken.
Because first promise is not resolved/rejected. Check following. I just changed return inn to resolve(inn)
function a() {
return new Promise((resolve, reject) => {
var inn = new Promise((resolve, reject) => {
setTimeout(() => reject('Error'), 0);
}).catch((msg) => console.log(msg));
resolve(inn);
});
}
a().then((msg) => console.log('then'));
Related
Normally, when a Promise in JavaScript rejects without handling, we get unhandled promise rejection error.
But then what happens to all rejected promises ignored by Promise.race logic? Why don't they throw the same error?
Consider the following test:
const normal = new Promise((resolve, reject) => {
setTimeout(() => resolve(123), 100);
});
const err = new Promise((resolve, reject) => {
setTimeout(() => reject('ops'), 500);
});
const test = Promise.race([normal, err]);
test.then(data => {
console.log(data);
});
The test above simply outputs 123, but no unhandled promise rejection error for our err promise.
I'm trying to understand what happens to all those rejected promises then, hence the question.
We potentially end up with a bunch of loose promises that continue running in the background, without any error handling, and never any reporting about unhandled promise rejections. This seems kind of dangerous.
Case in point. I was trying to implement combine logic for asynchronous iterables (similar to this), which requires use of Promise.race, while at the same time tracking rejections of any parameters passed into it, because the combine function needs then to reject on the next request.
Normally, when a Promise in JavaScript rejects without handling, we get
unhandled promise rejection error.
Yes, this happens when a promise is getting rejected that had never gotten .then() called on it to install handlers, i.e. one that is the final promise of a chain.
(Notice that .catch(onRejected) internally delegates tot .then(undefined, onRejected), so the promise is getting marked as handled the same.)
But then what happens to all rejected promises ignored by Promise.race logic? Why don't they throw the same error?
The Promise.race does call .then() on all promises in its argument, marking them as handled:
Promise.race = function(thenables) {
return new Promise((resolve, reject) => {
for (const thenable of thenables) {
Promise.resolve(thenable).then(resolve, reject);
}
});
};
Notice it doesn't re-throw the error when the outer promise is already resolved, it's just getting ignored. This is by design: when using Promise.race, you state that you are only interested in the first result, and everything else can be discarded. Causing unhandled promise rejections from the promises that didn't win the race to crash your application would be rather disruptive.
From MDN:
The Promise.race() method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise.
Your code fulfills because the faster promise calls resolve. Swap them around and it rejects.
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
}).catch((value) => {
console.log('error ', value);
});
I have this function:
export async function promisePlay(example: someInterface): Promise<string> {
const data = await fetch(example.url)
return new Promise((resolve, reject) => {
resolve("Lets test this")
console.log("This point shouldnt be reached");
})
}
When I run this I'm seeing the text This point shouldnt be reached in the console output. What I want (and thought) was that the resolve() should return and stop from running further.
Could someone please tell me what I'm fundamentally misunderstanding and how to correct?
Thanks.
resolve is a function in a variable.
You are calling the resolve function and passing the return value of the promise as the parameter.
However, that does not stop execution or break out.
If you want to exit the function, you must use return;.
Calling resolve does stop the pending await command of wherever you called the original function.
Whatever you value you pass to return will not be passed to the variable that resolves the promise and it will not stop the pending promise in the await command.
function test(yourWord)
{
return new Promise((resolve, reject) =>
{
// This will allow the command
// let res = await test("hello");
// to continue executing. It will stop executing on that line
// unless you call resolve or reject
resolve("you said: " + yourWord);
// this will continue to execute
console.log("I'm still alive");
// this string return value will be ignored
return "blah blah";
// this will not be executed since the function has returned
console.log("I'm dead");
});
}
(async () =>
{
// this will pause execution until resolve or reject is called and
// whatever value is passed into resolve() will be assigned to res
let res = await test("hello");
// this will echo out "you said hello"
console.log("res: " + res);
})();
You can return the resolve
export async function promisePlay(example: someInterface): Promise<string> {
const data = await fetch(example.url)
return new Promise((resolve, reject) => {
return resolve("Lets test this")
console.log("This point shouldnt be reached");
})
}
Promise body is synchronous, when you resolve the promise, it won't return(stop executing further statements).
I think you are confused between promises resolve and returning from them.
Consider below example,
new Promise((resolve) => {
console.log("inside promise");
resolve("promise resolved");
console.log("after resolving");
}).then(val => console.log(val));
In the above snippet, the console will print inside promise then after removing. It means it will execute all the statement in the promise first then it will wait for the promise to resolve. If you don't want to execute any statement further resolve, you can add return resolve in the function, cause its a normal function anyhow.
A JS promise has 3 states initial, fulfilled and rejected.
When awaiting a promise, the code waits for the state to change from initial to either rejected or resolved before execution continues.
When you await your promisePlay() function, execution will continue after the await as soon as reject() or resolve() is called.
Your case is special because you have code after you have resolved() within your promise.
It appears that during some experimentation of my own, it appears the JS engine waits until all the code is executed after the resolve(), I suppose its a bad idea to rely on this behaviour, as other answers suggest perhaps you should be return the result you want within in the resolve
In my script I need to make a XMLrequest, get the response from the server (if resolved), parse it and place the parsed result in a variable.
Only later, with this variable I can do lot of stuff.
So basically, I am trying to separate the creation of such parser object from the rest of my code, in order to:
place the above process into a function in an external script which I can call whenever I need.
not having all my code within a .then() method
organize my code into logical files each devoted to a specific task
So I came up with this piece of code (just a sample) to explain my needs.
As I am fairly new to asyncronous programming, would it be fine to do like so, given that the response should be very fast to resovle (or to reject) in my case?
If it's ok, I would then put this inside a separate file to be able to import it and call testing() (or whatever the name will be) from anywhere I need.
function delay(input) {
return new Promise(function(resolve, reject) {
// some async operation here
setTimeout(function() {
// resolve the promise with some value
resolve(input + 10);
}, 500);
});
}
function testing() {delay(5).then(result => {return document.write(result)})};
testing();
EDIT
Ok, so I think I hit the problem thanks to the answer of #DrewReese and the links in the comments.
I am trying to solve this situation: the code above was misleading to understand my point, but I guess tere's no really simple solution.
Look at this code (it's basically the same as the one above, except fot the last three lines):
function delay(input) {
return new Promise(function(resolve, reject) {
// some async operation here
setTimeout(function() {
// resolve the promise with some value
resolve(input + 10);
}, 500);
});
}
function testing() {delay(5).then(result => {return result})};
var test = testing();
document.write(test);
So in this case, I know when I am defining test the output is 'undefined' because the Promise in testing() has not yet resolved.
The problem I'm trying to solve is: is there (if any) a way to define test only when the Promise is resolved without wrapping it in a then() and maybe outputting something different when it's not resolved (like "LOADING...").
I don't know basically if it is possible to check if a variable has a Promise pending and outputting two different values: when it's waiting and when it's resolved/rejected.
Hopefully I was clear enough, otherwise I'll test more and come back with another question if needed.
The whole point of promises (promise chains) is to escape from "nesting hell" by flattening your "chain", so yes, when your promise chain is resolving blocks of code, it is returning a promise which is then-able. I hope this helps illustrate:
someAsyncHttpRequest(parameter) // <- Returns Promise
.then(result => {
// do something with result data, i.e. extract response data,
// mutate it, save it, do something else based on value
...
// You can even return a Promise
return Promise.resolve(mutatedData);
})
.then(newData => { // <- mutadedData passed as parameter
// do new stuff with new data, etc... even reject
let rejectData = processNewData(newData);
return Promise.reject(rejectData);
})
.catch(err => {
console.log('Any caught promise rejection no matter where it came from:', err);
})
.finally(() => {// You can even run this code no matter what});
If you need to use any variable values you set within the chain, then you need to make the outer function async and await on the resolution of the promise chain:
asyncFunction = async (parameter) => {
let asyncValue;
await someAsyncHttpRequest(parameter)
.then(result => {
...
asyncValue = someValue;
...
});
// safe to use asyncValue now
};
So for you:
function delay(input) {
return new Promise(function(resolve, reject) {
// some async operation here
setTimeout(function() {
// resolve the promise with some value
resolve(input + 10);
}, 500);
});
}
**async** function testing() { // Declare this an asynchronous function
let value = **await** delay(5); // Now you can await the resolution of the Promise
console.log(value); // Outputs resolved value 15!
return value; // Just returns resolved Promise
}
var test = testing();
console.log(test);
/** Outputs the Promise!
Promise {<pending>}
__proto__:Promise
[[PromiseStatus]]:"resolved"
[[PromiseValue]]:15
*/
test.then(console.log)); // Outputs returned resolved value, 15
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 this:
function sayHello() {
return new Promise( resolve => {
throw new Error('reject');
});
}
new Promise(resolve => sayHello()).then(ok => console.log('ok:', ok)).catch( err => console.error('err:', err) );
However the .catch never triggers. I though if I return a promise within a promise, it gets chained so that top level .then and .catch are re-reouted to child .then and .catch?
The problem is with your "new error" thrown at the Promise callback. Throwing an error inside promise executor does not automatically reject it.
Edit: actually Promise executor does automatically reject the promise when an exception is thrown. Nevertheless, this is not the main cause of your problem. Also a note - throwing will only work on the "main" level of executor, so any asynchronous job throwing an exception won't automatically reject the promise.
Another problem spotted - your Promise chain (new Promise(resolve => sayHello())...) is also invalid - you are simply returning a function call result. You always have to manually resolve or reject a Promise that you've created with it's standard constructor (aka. new Promise(executorCallback)).
To fix the other problem, you can use "automatically resolved promise", which I think will do what you are trying to achieve:
Promise.resolve(sayHello()).then(...)
So in the end, your code should look like this (using the gist you have posted in the comment below by answer):
function sayHello() {
return new Promise( (resolve,reject) => {
reject('rawr')
});
}
Promise.resolve(sayHello()).then(ok => console.log('ok:', ok)).catch( err => console.error('err:', err) );