I am having an error: (node:6186) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): threep
(node:6186) [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.
-------- ones
========= two
CaughtCathchError threep
(node:6186) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
I am consuming my 3 promise functions in nested order.
p1,p2,p3- are my promise functions as shown below.
i tried adding promise reject in all p1,p2,p3 functions as well but its still the same
enter code here
var p1 = new Promise(function (resolve, reject) {
setTimeout(function () {
// resolve('ones')
resolve('ones')
}, 9000)
})
var p2 = new Promise(function (resolve, reject) {
setTimeout(function () {
// throw new Error('eeeee');
//reject('two')
resolve('two')
}, 1000)
})
var p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
reject('three')
}, 4000)
})
p1.then(function(result){
console.log("--------", result)
// return p2.then(function(res){console.log(res)}).catch(function(err){console.log(err)})
return p2
}).then(function(p2result){
console.log("=========", p2result)
return p3;
}).then(function(p3result){
console.log('*********', p3result)
}).catch(function(err){
console.log("CaughtCathchError", err)
})
p3 is a standalone Promise with no .catch. So, when p3 gets rejected, you get a UnhandledPromiseRejectionWarning. Even if p3 is consumed later in a Promise chain that has a proper catch, p3 itself does not have a catch.
Instead of p3, you might use a function that returns a Promise, and ensure that all calls to that function are caught:
var p1 = new Promise(function (resolve, reject) {
setTimeout(function () {
// resolve('ones')
resolve('ones')
}, 1000)
})
var p2 = new Promise(function (resolve, reject) {
setTimeout(function () {
// throw new Error('eeeee');
//reject('two')
resolve('two')
}, 1000)
})
var getp3 = () => new Promise(function (resolve, reject) {
setTimeout(function () {
reject('three')
}, 1000)
})
p1.then(function(result){
console.log("--------", result)
// return p2.then(function(res){console.log(res)}).catch(function(err){console.log(err)})
return p2
}).then(function(p2result){
console.log("=========", p2result)
return getp3();
}).then(function(p3result){
console.log('*********', p3result)
}).catch(function(err){
console.log("CaughtCathchError", err)
})
If you need to initialize p3 immediately, then put a catch after the p3 itself.
Node.js promise implementation expects rejected promise to be chained with catch(...) or then(..., ...) synchronously, otherwise PromiseRejectionHandledWarning appears. Unhandled promise rejections may result in exception in future.
Usually a rejection should be treated as any other error, so it's preferable for it to be an instance of Error and not plain string. Then it could be treated as such:
class ExpectedRejection extends Error {}
var p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(new ExpectedRejection('three'))
}, 4000)
})
...
.then(function(p3result){
if (p3result instanceof ExpectedRejection)
throw p3result;
console.log('*********', p3result)
}).catch(function(err){
console.log("CaughtCathchError", err)
})
ExpectedRejection class is specific and possibly not needed; could be replaced with Error everywhere because Error resolutions are uncommon.
This solution is not very common because if promises are created at the same time, they don't depend on each other and usually can be handled with Promise.all:
Promise.all([p1, p2, p3])
.then(function(p1result, p2result, p3result){
console.log('*********', p3result)
}).catch(function(err){
console.log("CaughtCathchError", err)
});
Notice that since p1, p2 and p3 are delays that are created at the same time, resulting catch will be triggered after 9 seconds (maximum duration of a delay) in both cases.
If you want to create a rejecting/rejected promise that will be caught on the queue and not on the stack then you could do the following:
var p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
reject('three')
}, 400)
});
//do not warn for p3 rejection but if you use it later (p3.then) or
// return it in a promise chain you will have to catch it again
p3.catch(ignore=>ignore);
Related
This question already has an answer here:
Weird behavior with Promise throwing "Unhandled promise rejection" error
(1 answer)
Closed 3 years ago.
I am using a "defer" pattern for Javascript promises that lets me return a promise to a calling function, and then at a later time, on some conditions, resolve or reject that promise.
As you can see in my code provided, everything is working as expected EXCEPT for the fact that in the browser, I get an Unhandled Rejection error.
function promiseGenerator() {
const deferred = {};
const promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});
deferred.promise = promise;
return deferred;
}
const generatedPromise = promiseGenerator();
generatedPromise.promise.then(res => {
console.log("A string deferred resolved!", res);
});
generatedPromise.promise.then().catch(e => {
console.log("This is the catch", e);
});
generatedPromise.reject("Oh no");
I'm expecting to see This is the catch Oh no in the console - and I do. But why am I getting the error? Clearly my rejection is being handled!
NOTE that I don't (necessarily) want to chain the catch to the then because I may want to add this catch somewhere else, separately, in the code
Here is a Codesandbox link
https://codesandbox.io/embed/deferred-promise-catch-vanilla-pjor9
The Promise rejections are not handled in the .then() callback, when you attach the then() callback first and the promise is rejected the error is considered to be unhandled as there is no catch() following the then().
The proper way to handle this is to add a catch() chained to the then():
function promiseGenerator() {
const deferred = {};
const promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});
deferred.promise = promise;
return deferred;
}
const generatedPromise = promiseGenerator();
//Error from the rejection is handled in the catch
generatedPromise.promise.then(res => {
console.log("A string deferred resolved!", res);
}).catch(e => {
console.log("This is the catch", e);
});
generatedPromise.reject("Oh no");
Another way is to pass a rejection handler as the second parameter of the then() callback to handle the Promise rejection:
function promiseGenerator() {
const deferred = {};
const promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});
deferred.promise = promise;
return deferred;
}
const generatedPromise = promiseGenerator();
//Error from the rejection is handled in the second callback
generatedPromise.promise.then(res => {
console.log("A string deferred resolved!", res);
},
err => {
console.log("This is the catch", err);
});
generatedPromise.reject("Oh no");
In order to catch errors thrown in the callback you passed to the new Promise() constructor, the catch block needs to be appended to returned value of .then(), not to the promise itself.
generatedPromise.promise
.then(res => {
console.log("A string deferred resolved!", res);
})
.catch(e => {
console.log("This is the catch", e);
});
The generatedPromise.reject object is a reference to the reject argument inside the callback you passed to the constructor (resolve, reject) => {}.
On the same note, generatedPromise.promise is a reference to the object returned by new Promise().
Then only way you can catch an error thrown by calling genetratedPromise.reject() is by chaining a .catch() to the .then(). There is no other way.
Here's another way of seeing this problem:
const promise = new Promise((resolve, reject) => {
reject('test')
});
promise.catch(err => 'foo'); // throws unhandled promise rejection. Cause you rejected, but didn't catch it after the .then statement
promise.then(() => {}).catch(err => 'foo'); // doesn't throw rejection
You use catch in a promise chain.
generatedPromise.promise.then(res => {
console.log("A string deferred resolved!", res);
}).catch(error => console.log('error));
Edit:Someone was faster.
Edit2: Seen comment on other post. There might be a way, but it's not good practice.
function promiseGenerator() {
const deferred = {};
//do your function stuff here
try{
const promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
});
} catch(ex){
const promise = new Promise((resolve, reject) => {
deferred.resolve = resolve(ex);
});
}
return deferred;
}
This way you have two different results for one promise, other way is to use instead of try catch block, if else statements, but it solely depends on your application.
I'm trying to make promises work, and so far i've stumbled on this:
new Promise((resolve, reject) => {
setTimeout(() => {
return resolve()
}, 400)
}).then(new Promise((resolve, reject) => {
setTimeout(() => {
return reject('some error')
}, 100)
})).then(() => {
console.log('All promises resolved')
}).catch((err) => {
console.log('Error: ' + err)
})
My understanding is that this example should display Error: some error, with the first promise successfully resolving, and the second one throwing an error. But when i run this (in node 9.7, if that matters) i get this error:
(node:10102) UnhandledPromiseRejectionWarning: some error
(node:10102) 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:10102) [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.
All promises resolved
My .catch() doesn't seem to be working, is there a problem with it ?
You are actually passing promise, instead of function.
You should write your code like this:
new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 400)
}).then(() => new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('some error'))
}, 100)
})).then(() => {
console.log('All promises resolved')
}).catch((err) => {
console.log('Error: ' + err)
})
I have a list of promises.
var p1 = {
run: function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("Promise 1 done");
}, 2000);
})
}
};
var p2 = {
run: function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject("Promise 2 reject");
}, 1000);
})
}
};
var p3 = {
run: function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("Promise 3 done");
}, 1500);
})
}
};
I want to execute [p1,p2,p3] in sequence. I writed a function Process.sequence to act like Promise.all() (resolve when all promises resolve, and reject right after a promise rejects)
Process = {
sequence: function(promises){
window.promises = promises;
return new Promise(function (resolve, reject) {
promises.reduce(function (sequence, promise) {
return sequence.then(function () {
return promise.run();
}).then(function (result) {
console.log(result);
if (promises.indexOf(promise) == promises.length - 1) {
resolve("All Done");
}
}).catch(function (reason) {
reject(reason);
});
}, Promise.resolve());
});
}
};
But when i run Process.sequence...
Process.sequence([p1,p2,p3]).then(function(result){
console.log(result);
}, function(reason){
console.log(reason);
});
... the p3 still executed even p2 had rejected before.
Here is the result i expect:
Promise 1 done
Promise 2 reject
But this is the real result:
Promise 1 done
Promise 2 reject
Promise 3 done
What wrong with my function Process.sequence?
UPDATE
Thank #JaromandaX for your support. The function Process.sequence should be like this.
Process = {
sequence: function(promises) {
return promises.reduce(function(sequence, promise) {
return sequence.then(function() {
return promise.run();
}).then(function(result) {
console.log(result);
});
}, Promise.resolve()).then(function() {
return "All Done";
});
}
};
As you want the results to contain all of the fulfilled values, and the promises only to be created ("run") when all previous ones were fulfilled, you should make some changes:
Make your loop asynchronous, as you can only know whether to continue with the next promise or not when the previous one has resolved.
Stop looping when a promise rejects
Concatenate the results in an array as you progress
Furthermore, I would not call a variable "promise" when it is not a promise object... that will only bring confusion. Call it task or something. The promise here is what the task.run() method returns.
Here is how I would suggest to do it:
// The p1, p2, p3 objects have been written more concisely using a helper function:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
const p1 = { run: _ => wait(2000).then(_ => "Promise 1 fulfilled") };
const p2 = { run: _ => wait(1000).then(_ => { throw "Promise 2 rejected" }) };
const p3 = { run: _ => wait(1500).then(_ => "Promise 3 fulfilled") };
const Process = {
sequence: function (tasks) {
return (function loop(results) {
return results.length >= tasks.length
// All promises were fulfilled: return the results via a promise
? Promise.resolve(results)
// Create the next promise
: tasks[results.length].run()
// When it fulfills, collect the result, and chain the next promise
.then(value => loop(results.concat(value)))
// When it rejects, return a rejected promise with
// the partial results and the reason of rejection
.catch(reason => { throw results.concat(reason) });
})([]); // Start with an empty results array
}
};
console.log('Wait for the results to come in...');
Process.sequence([p1, p2, p3]).then(function(result){
console.log('Fulfilled: ', result);
}).catch(function(reason){
console.log('Rejected: ', reason);
});
As browsers have started to support async/await you could also use this more procedural looking code:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
const p1 = { run: _ => wait(2000).then(_ => "Promise 1 fulfilled") };
const p2 = { run: _ => wait(1000).then(_ => { throw "Promise 2 rejected" }) };
const p3 = { run: _ => wait(1500).then(_ => "Promise 3 fulfilled") };
const Process = {
sequence: async function (tasks) {
const results = [];
for (let task of tasks) {
try {
results.push(await task.run());
} catch(err) {
throw results.concat(err);
}
}
return results;
}
};
console.log('Wait for the results to come in...');
Process.sequence([p1, p2, p3]).then(function(result){
console.log('Fulfilled: ', result);
}).catch(function(reason){
console.log('Rejected: ', reason);
});
Below outlines a promise that has two simple steps display on the console something, then display something else after the first step is completed.
I am trying to understand how to resolve the promise, and allow the 2nd step to complete.
var lookup_documents = new Promise(
function(resolve, reject) {
console.log("1st");
//resolve(); - How do I do this outside of this function?
}
);
lookup_documents.then(
function() {
console.log("2nd");
}
);
Normally you use new Promise() when you want to wrap some asynchronous function into a promise, such as:
new Promise((resolve, reject) => {
makeAjaxCall((err, data) => {
if(err) return reject(err);
else return resolve(data);
})
});
There are other Promise implementations, such as q, where you can create a "deferred" object that returns a promise... Something similar would be:
function makeAjaxCallPromise() {
let deferred = Q.defer();
makeAjaxCall((err, data) => {
if(err) return deferred.reject(err);
else return deferred.resolve(data);
});
return deferred.promise;
}
For the specific thing you want... All I can think of is declare a variable outside of the promise function scope and asign it, something like:
let resolver, rejecter;
new Promise((resolve, reject) => {
resolver = resolve;
rejecter = reject;
});
makeAjaxCall((err, data) => {
if(err) return resolver(err);
else return rejecter(data);
});
But that doesn't look too good and can lead to errors... Try to wrap everything in your Promise function.
You can do it like this, using your example - if I understand you correctly.
var lookup_documents = function() {
return new Promise(function(resolve, reject) {
console.log("1st");
resolve();
});
};
lookup_documents().then(function() {
console.log("2nd");
});
I'm having problmes in finding the use of promises and also admit that my understanding of them is very basic. From what I can tell, they just seem to mimic sync behavior.
Is it possible to use promises and keep the async behaviour then use then() once they have all completed?
Such as this...
var fileRegister = [ 'fileA', 'fileB', 'fileC' ];
for( i in fileRegister ) {
asyncLoadFile( fileRegister[ i ], function( err, data ) {
delete fileRegister[ i ];
if ( ! fileRegister.length ) {
console.log('done');
}
});
}
Yes, you can use Promise.all to wait on multiple promises:
var fileRegister = [ 'fileA', 'fileB', 'fileC' ];
// returns a promise for a file
function loadFile(filename) {
return new Promise(function (resolve, reject) {
asyncLoadFile(filename, function (err, data) {
if (err) {
reject(err);
}
resolve(data);
});
});
}
Promise.all(fileRegister.map(loadFile))
.then(function (files) {
console.log("done");
});
I'm truly surpised there seems to be no authoratative answer for this on the site. Yes, you can create a bunch of promises (each wrapping an async operation) and then call Promise,all which will resolve once they all do:
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 2000, "two");
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 3000, "three");
});
var p4 = new Promise(function(resolve, reject) {
setTimeout(resolve, 4000, "four");
});
var p5 = new Promise(function(resolve, reject) {
reject("reject");
});
Promise.all([p1, p2, p3, p4, p5]).then(function(value) {
console.log(value);
}, function(reason) {
console.log(reason)
});
This is part of the E^ specification and is supported by most implementations.