What happens to rejected promises inside Promise.race? - javascript

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);
});

Related

Cannot understand why outer Promise wont resolve

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'));

How to handle an unhandled promise rejection asynchronously?

I'm trying to wrap my head around this issue I'm facing concerning async/await and Promises. I managed to boil my issue down to the following code:
async function sleep(ms: number) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
async function fetchMock(): Promise<any> {
return new Promise(() => {
throw 'error fetching result';
});
}
async function main(): Promise<any> {
const kickedOffRequest = fetchMock();
await sleep(10);
return kickedOffRequest;
}
main()
.then(() => console.log('resolved promise!'))
.catch(error => console.error('caught error!', error));
I receive the following warning:
(node:82245) UnhandledPromiseRejectionWarning: error fetching result
(node:82245) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:82245) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
caught error! error fetching result
(node:82245) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
You can observe the same issue in this sandbox. I noticed that commenting out the await sleep(10) fixes the issue, but I apparently know less about promises than I thought. Why does commenting that line out make my program work? I'm tempted to ask how to fix the Promise rejection was handled asynchronously error, but I hope that once I understand how await sleep(10) causes the error I get I will be able to fix this one on my own.
Thanks in advance for taking the time to read/answer this question!
The original concept of promises was that you could have a rejected promise sitting around for some time before attaching a catch handler to it. For example, Firefox used to warn of uncaught rejection errors only when a rejected promise with no rejection handler was garbage collected from memory.
Somebody decided that programmers couldn't be trusted with managing promise rejections properly and changed the HTML spec to require browsers to throw "unhandled promise rejection" errors if a rejected promise has no rejection handlers added before code returns to the event loop.
(I think unhandled rejections can survive without error in the micro task queue for a tick or two, before control returns to the event loop proper, but haven't tested it lately.)
The ECMAScript specification added an abstract means of notifying the host environment of an unhandled promise rejection without specifying what, if any, action should be taken.
On a case by case basis you can prevent the host being notified by adding a rejection handler that is never used. The reasoning is that adding a dummy rejection handler to a promise means that should it be rejected it has a rejection handler already - or if it was rejected the host is notified the promise now has a rejection handler - and you can call then and catch multiple times on the same promise.
Changing
async function fetchMock(){
return new Promise(() => {
throw 'error fetching result';
});
}
to
async function fetchMock(){
let promise = new Promise(() => {
throw 'error fetching result';
});
promise.catch(()=>null); // unused rejection handler
return promise;
}
should work around the unwanted HTML5 host behavior implemented in V8, the JavaScript engine used in node.
The detection of unhandled rejection in node.js is imperfect. There are specific spots in the life cycle of a rejected promise where the engine checks to see if there's a handler and it does not always wait until the last possible moment so it can miss places that you add a handler. In your specific case, you may need to attach a .catch() handler locally, then finish up the work you want to do, then rethrow the error. This work-around will work for you while still maintaining the desired resolve/reject from main() (e.g. without changing the interface to main).
So, this isn't particularly super pretty, but it meets the spec we talked about in comments.
main() calls fetchMock()
If it resolves or rejects quickly (before some custom delay time), then it holds off on the resolve or the reject until at least that delay time has elapsed from when fetchMock() was originally called.
If fetchMock() takes longer than that custom delay time to resolve or reject, then no further delay is added.
The promise that main() returns then follows the promise that fetchMock() returned, either rejected or resolved with the same reason or value.
The key ingredient is that it captures the time right before calling fetchMock() and then when fetchMock() either resolves or rejects, it decides whether to delay any more time before passing the resolve/reject value/reason on through.
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
function fetchMock() {
return new Promise((resolve) => {
throw 'error fetching result';
//resolve('this is our result');
});
}
function handler(start, minWaitTime, isErr = false) {
return async function(val) {
let diff = minWaitTime - (Date.now() - start);
if (diff > 0) {
await sleep(diff);
}
if (isErr) {
throw val;
} else {
return val;
}
}
}
function main() {
let start = Date.now();
const minWaitTime = 1000;
return fetchMock().then(handler(start, minWaitTime), handler(start, minWaitTime, true));
}
main()
.then(() => console.log('resolved promise!'))
.catch(error => console.error('caught error!', error));
Note, also that sleep() and fetchMock() already directly return promises and don't use await so there is no requirement for them to be async.
The problem is that the fetchMock rejects immediately, and when a Promise rejects, at the time that it rejects, it must be chained with a .catch somewhere in order to prevent an Unhandled Promise Rejection.
With your await sleep(10), the kickedOffRequest promise rejects while the main function is still waiting for sleep to resolve. When there's a rejection, the interpreter doesn't look ahead to see if the Promise may be caught in the future (for example, to see if the Promise gets returned or caught) - the Promise must be caught now.
When you remove the await, kickedOffRequest still becomes a rejected Promise, but it's returned from main immediately, so at the point that the Promise rejects, it can be seen and caught by the outer .catch, so there's no Unhandled Rejection warning.
It's good if a Promise rejection can be handled right when it rejects, but if that's not an option for you, you can put another .catch onto the end of the inner Promise. That way, the warning won't appear (because of the existence of .catch, even if that .catch didn't do anything meaningful) and you can later check to see if an error actually occurred or not:
async function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
async function fetchMock(){
return new Promise(() => {
throw 'error fetching result';
});
}
async function main() {
const kickedOffRequest = fetchMock()
.then(resolved => ({ resolved }))
.catch(rejected => ({ rejected }));
await sleep(10);
return kickedOffRequest;
}
main()
.then(({ resolved, rejected }) => {
if (resolved) {
console.log('resolved promise!');
} else {
console.error('caught error!', rejected);
}
});
This is pretty similar to how Promise.allSettled works (though it's more intended for when there's an array of Promises that need to be parsed):
async function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
async function fetchMock(){
return new Promise(() => {
throw 'error fetching result';
});
}
async function main() {
const kickedOffRequestArr = Promise.allSettled([fetchMock()]);
await sleep(10);
return kickedOffRequestArr;
}
main()
.then(([{ result, reason, value }]) => {
if (result === 'fulfilled') {
console.log('resolved promise!', value);
} else {
console.error('caught error!', reason);
}
});

trying to use .then() in my server side script which uses node js but i get an error [duplicate]

For learning Angular 2, I am trying their tutorial.
I am getting an error like this:
(node:4796) UnhandledPromiseRejectionWarning: Unhandled promise rejection (r ejection id: 1): Error: spawn cmd ENOENT
[1] (node:4796) DeprecationWarning: Unhandled promise rejections are deprecated.
In the future, promise rejections that are not handled will terminate the Node.
js process with a non-zero exit code.
I went through different questions and answers in SO but could not find out what an "Unhandled Promise Rejection" is.
Can anyone simply explain me what it is and also what Error: spawn cmd ENOENT is, when it arises and what I have to check to get rid of this warning?
The origin of this error lies in the fact that each and every promise is expected to handle promise rejection i.e. have a .catch(...) . you can avoid the same by adding .catch(...) to a promise in the code as given below.
for example, the function PTest() will either resolve or reject a promise based on the value of a global variable somevar
var somevar = false;
var PTest = function () {
return new Promise(function (resolve, reject) {
if (somevar === true)
resolve();
else
reject();
});
}
var myfunc = PTest();
myfunc.then(function () {
console.log("Promise Resolved");
}).catch(function () {
console.log("Promise Rejected");
});
In some cases, the "unhandled promise rejection" message comes even if we have .catch(..) written for promises. It's all about how you write your code. The following code will generate "unhandled promise rejection" even though we are handling catch.
var somevar = false;
var PTest = function () {
return new Promise(function (resolve, reject) {
if (somevar === true)
resolve();
else
reject();
});
}
var myfunc = PTest();
myfunc.then(function () {
console.log("Promise Resolved");
});
// See the Difference here
myfunc.catch(function () {
console.log("Promise Rejected");
});
The difference is that you don't handle .catch(...) as chain but as separate. For some reason JavaScript engine treats it as promise without un-handled promise rejection.
This is when a Promise is completed with .reject() or an exception was thrown in an async executed code and no .catch() did handle the rejection.
A rejected promise is like an exception that bubbles up towards the application entry point and causes the root error handler to produce that output.
See also
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
Promises can be "handled" after they are rejected. That is, one can call a promise's reject callback before providing a catch handler. This behavior is a little bothersome to me because one can write...
var promise = new Promise(function(resolve) {
kjjdjf(); // this function does not exist });
... and in this case, the Promise is rejected silently. If one forgets to add a catch handler, code will continue to silently run without errors. This could lead to lingering and hard-to-find bugs.
In the case of Node.js, there is talk of handling these unhandled Promise rejections and reporting the problems. This brings me to ES7 async/await. Consider this example:
async function getReadyForBed() {
let teethPromise = brushTeeth();
let tempPromise = getRoomTemperature();
// Change clothes based on room temperature
let temp = await tempPromise;
// Assume `changeClothes` also returns a Promise
if(temp > 20) {
await changeClothes("warm");
} else {
await changeClothes("cold");
}
await teethPromise;
}
In the example above, suppose teethPromise was rejected (Error: out of toothpaste!) before getRoomTemperature was fulfilled. In this case, there would be an unhandled Promise rejection until await teethPromise.
My point is this... if we consider unhandled Promise rejections to be a problem, Promises that are later handled by an await might get inadvertently reported as bugs. Then again, if we consider unhandled Promise rejections to not be problematic, legitimate bugs might not get reported.
Thoughts on this?
This is related to the discussion found in the Node.js project here:
Default Unhandled Rejection Detection Behavior
if you write the code this way:
function getReadyForBed() {
let teethPromise = brushTeeth();
let tempPromise = getRoomTemperature();
// Change clothes based on room temperature
return Promise.resolve(tempPromise)
.then(temp => {
// Assume `changeClothes` also returns a Promise
if (temp > 20) {
return Promise.resolve(changeClothes("warm"));
} else {
return Promise.resolve(changeClothes("cold"));
}
})
.then(teethPromise)
.then(Promise.resolve()); // since the async function returns nothing, ensure it's a resolved promise for `undefined`, unless it's previously rejected
}
When getReadyForBed is invoked, it will synchronously create the final (not returned) promise - which will have the same "unhandled rejection" error as any other promise (could be nothing, of course, depending on the engine). (I find it very odd your function doesn't return anything, which means your async function produces a promise for undefined.
If I make a Promise right now without a catch, and add one later, most "unhandled rejection error" implementations will actually retract the warning when i do later handle it. In other words, async/await doesn't alter the "unhandled rejection" discussion in any way that I can see.
to avoid this pitfall please write the code this way:
async function getReadyForBed() {
let teethPromise = brushTeeth();
let tempPromise = getRoomTemperature();
// Change clothes based on room temperature
var clothesPromise = tempPromise.then(function(temp) {
// Assume `changeClothes` also returns a Promise
if(temp > 20) {
return changeClothes("warm");
} else {
return changeClothes("cold");
}
});
/* Note that clothesPromise resolves to the result of `changeClothes`
due to Promise "chaining" magic. */
// Combine promises and await them both
await Promise.all(teethPromise, clothesPromise);
}
Note that this should prevent any unhandled promise rejection.
"DeprecationWarning: Unhandled promise rejections are deprecated"
TLDR: A promise has resolve and reject, doing a reject without a catch to handle it is deprecated, so you will have to at least have a catch at top level.
In my case was Promise with no reject neither resolve, because my Promise function threw an exception. This mistake cause UnhandledPromiseRejectionWarning message.
I was seeing this when I had a util file with a Promised API call, a component that calls it but wasn't explicitly handling the .catch, and a Jest that was mocking up a Promise.reject:
fetchStuff.mockImplementationOnce(() => Promise.reject(new Error('intentional fail')));
Furthermore, this was poisoning my mock, so that even though I was calling jest.resetAllMocks() before each test, the very next test would try render and that render would call the API, and it would fail. The test after would be back to a good state. I could swap around the order of my tests to prove that it would always poison the next render.
I tried handling the error in the API, but didn't succeed. I tried handling in my Jest mock, but that didn't work, either. What I ended up having to do was explicitly handle the .catch in my component.
I had faced a similar issue with NodeJS, where the culprit was a forEach loop. Note that forEach is a synchronous function (NOT Asynchronous). Therefore it just ignores the promise returned.
The solution was to use a for-of loop instead:
Code where I got the error:
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch()
is as follows:
permissionOrders.forEach( async(order) => {
const requestPermissionOrder = new RequestPermissionOrderSchema({
item: order.item,
item_desc: order.item_desc,
quantity: order.quantity,
unit_price: order.unit_price,
total_cost: order.total_cost,
status: order.status,
priority: order.priority,
directOrder: order.directOrder
});
try {
const dat_order = await requestPermissionOrder.save();
res.json(dat_order);
} catch(err){
res.json({ message : err});
}
});
Solution for the above issue is as follows:
for (let order of permissionOrders){
const requestPermissionOrder = new RequestPermissionOrderSchema({
item: order.item,
item_desc: order.item_desc,
quantity: order.quantity,
unit_price: order.unit_price,
total_cost: order.total_cost,
status: order.status,
priority: order.priority,
directOrder: order.directOrder
});
try {
const dat_order = await requestPermissionOrder.save();
res.json(dat_order);
} catch(err){
res.json({ message : err});
}
};
Try not closing the connection before you send data to your database. Remove client.close(); from your code and it'll work fine.
When I instantiate a promise, I'm going to generate an asynchronous function. If the function goes well then I call the RESOLVE then the flow continues in the RESOLVE handler, in the THEN. If the function fails, then terminate the function by calling REJECT then the flow continues in the CATCH.
In NodeJs are deprecated the rejection handler. Your error is just a warning and I read it inside node.js github. I found this.
DEP0018: Unhandled promise rejections
Type: Runtime
Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Javascript Promises, Returned Promise of then and catch method

Was fooling around a bit with Promises, here is the code:
let prom1 = new Promise((res, rej) => {
res('res');
});
const resolvedProm1 = prom1.then((val) => {
return val
});
console.log(resolvedProm1);
let prom2 = new Promise((res, rej) => {
rej('rej');
});
const resolvedProm2 = prom2.catch((err) => {
return err
});
console.log(resolvedProm2);
The chrome devtools shows the following information about the promises:
However, I didn't expect this particular output. What I expected was the following:
Both resolvedProm1 and resolvedProm2 would be <fullfilled> Promises instead of <pending>. Why are they pending and not fullfilled?
The resolvedProm2 was rejected, why does the promiseStatus shows that it is resolved?
In both cases promises printed before they are resolved. What you send into promise context will always execute after your current callstack unwinds, so consoles till the end of a function run first.
Both resolvedProm1 and resolvedProm2 would be Promises instead of . Why are they pending and not fullfilled?
Because they are resolved asynchronously. You were logging them while they still were pending. You'll notice if you put some console.log statements in your then and catch callbacks that the callbacks weren't executed yet as well.
You only get the [[PromiseStatus]] as "resolved" (which really should be "fulfilled") when you inspect the promise value in the devtools, which you do after they were resolved.
The resolvedProm2 was rejected, why does the promiseStatus shows that it is resolved?
No, you were rejecting the prom2. The resolvedProm2 is the result of the .catch() invocation, whose callback did handle the rejection and returned a non-error result.

How to decide which promise does a then/catch according to

All:
I am pretty new to Promise, here is an example:
var someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// this will throw, x does not exist
resolve(x + 2);
});
};
var someOtherAsyncThing = function() {
return new Promise(function(resolve, reject) {
reject('something went wrong');
});
};
someAsyncThing().then(function() {
return someOtherAsyncThing();
}).catch(function(error) {
console.log('oh no', error);
});
I do not quite get how .then() works with Promise, right now I can understand the someAsyncThing() return a Promise, which will generate an exception and thus go to .catch() part. And if we change resolve(x+2) to resolve(4), then it will go to run someOtherAsyncThing(); and return another promise,
the first question is if the return of .then() is the that Promise?
And second question, if in someOtherAsyncThing()'s Promise, I use resolve(x+2) to cause an exception, then it will also go to same .catch() part, then how can I make that .catch() only catch exception caused by someAsyncThing()'s promise(and same question for chained .then() if there is any)?
Thanks
the first question is if the return of .then() is the that Promise?
p.then() returns a promise - always. If the callback passed to the .then() handler returns a value, then the newly returned promise will be resolved at the same time as the parent promise, but will be resolved with the returned value from the handler.
If the .then() handler returns a promise, then the promise returned by .then() is not fulfilled/rejected until the promise returns by the handler is fullfilled/rejected. They are chained together.
If the .then() handler throws, then the promise returned by .then() is
rejected with the exception as the value. Throwing is the same as returning a rejected promise.
if in someOtherAsyncThing()'s Promise, I use resolve(x+2) to cause
an exception, then it will also go to same .catch() part, then how
can I make that .catch() only catch exception caused by
someAsyncThing()'s promise(and same question for chained .then()
if there is any)?
The beauty of promises is that errors propagate up the chain until handled. The way you stop err propagation at any level is to handle the error there.
If you want to separate the .catch() opportunities, then you have to just catch at a lower level. For example:
someAsyncThing().then(function() {
return someOtherAsyncThing().catch(function(err) {
// someOtherAsyncThing rejected here
// you can handle that rejection here and decide how you want to proceed
// for example, suppose you just want to handle the rejection, log it
// and then continue on as if there was no problem, you can just return
// a value here
return 0;
});
}).catch(function(error) {
console.log('oh no', error);
});
Errors bubble up in promises until they're caught.
If you have the following (<= indicates contains):
Promise1 <= Promise2.catch(e) <= Promise3 <= throw
Then Promise3 throws and rejects. Promise2 rejects and then is caught. Promise1 resolves successfully because it receives no rejection.
Promise1 <= Promise2.catch(e) <= Promise3 <= throw
^ resolves ^ rejects ^ rejects
Think of it as an async try/catch.
Promise1 = Promise.reject(err); // or throw
Promise2 = Promise1.catch(err => {
// error caught
});
Promise3 = Promise1.catch(err => {
throw err;
// error not caught but thrown back
});
// Now Promise1 is rejected. Promise2 is resolved. Promise3 is rejected.
You also need to know that each then/catch call creates a new Promise. I suggest you read the Promises/A+ spec and keep it as a reference.
You can catch() on the inner Promise:
a().then(function() {
return b().catch(function() {
console.log('boo');
});
}).catch(function(error) {
console.log('oh no', error);
});
If a() rejects, "oh no" will be logged. If b() rejects, "boo" will be logged, but not "oh no".

Categories

Resources