I am trying to write a Javascript promise that resolves and rejects the desired variables. I am getting the error message below after running in the console
[UnhandledPromiseRejection: 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().
code: 'ERR_UNHANDLED_REJECTION'
Here is my code
Js File:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
let grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject("User Left");
} else if (userWatchingGrimeVids) {
reject("This user is a G");
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise.then((message) => {
console.log("Success: " + message);
});
grimePromise.catch((message) => {
console.log("You Failed: " + message);
});
By calling the .then() and the .catch() handler on two different places, you actually end up with two different promises - each of .then() and .catch() returns a new one. The promise returned by .then() will not be caught by the separate .catch() handler:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
let grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject("User Left");
} else if (userWatchingGrimeVids) {
reject("This user is a G");
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise
.then((message) => {
console.log("Success: " + message);
})
.catch(() => console.log(1));
grimePromise.catch((message) => {
console.log(2);
console.log("You Failed: " + message);
});
Therefore, one promise gets turned into two. Each of them will adopt the state of the original promise. When the original is rejected, both the derived promises reject. Yet only one is handled.
Instead, you can directly specify the .catch() in the same promise chain as the .then():
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
let grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject("User Left");
} else if (userWatchingGrimeVids) {
reject("This user is a G");
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise
.then((message) => {
console.log("Success: " + message);
})
.catch((message) => {
console.log("You Failed: " + message);
});
<h1>Check the browser console - no unhandled promise rejections</h1>
Or alternatively, specify both handlers in the then():
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
let grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject("User Left");
} else if (userWatchingGrimeVids) {
reject("This user is a G");
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise
.then(
(message) => {
console.log("Success: " + message);
},
(message) => {
console.log("You Failed: " + message);
}
);
<h1>Check the browser console - no unhandled promise rejections</h1>
The reason this isn't working is because you didn't have a .catch() on the first one. It was throwing a rejection, but you weren't handling it gracefully with a catch, so it threw.
Here is your code working - I just moved your catch block to go after the .then:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
const grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject('User Left');
} else if (userWatchingGrimeVids) {
reject('This user is a G');
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise
.then((message) => {
console.log('Success: ' + message);
})
.catch((message) => {
console.log('You Failed: ' + message);
});
Just as a tip though, you should only reject whenever the function is unsuccessful in some way. That could be a timeout, a network error, incorrect input etc. Whatever is inside of a reject should ideally be an error.
Additionally, I'd recommend using async await, as it's much easier to read and more manageable. You can easily do this by creating a function which returns your new Promise, then awaiting it like so:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
const grime = () => {
return new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject(new Error('User Left'));
} else if (userWatchingGrimeVids) {
resolve('This user is a G');
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
};
const doStuff = async () => {
try {
const result = await grime();
console.log(result);
} catch (error) {
console.error(error);
}
};
doStuff();
To make this truly asynchronous, you should ideally be doing some async stuff inside of the promise. This can be demonstrated with a setTimeout:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
const grime = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (grimeUserLeft) {
reject(new Error('User Left'));
} else if (userWatchingGrimeVids) {
resolve('This user is a G');
} else {
resolve("Congrats. Your channel doesn't suck");
}
}, 2000);
});
};
const doStuff = async () => {
try {
const result = await grime();
console.log('result finished after 2 seconds');
console.log(result);
} catch (error) {
console.error(error);
}
};
doStuff();
Related
im trying to write a promise but seems to be missing something. here is my code:
const myPromise = new Promise(() => {
setTimeout(() => {
console.log("getting here");
return setinputs({ ...inputs, images: imageAsUrl });
}, 100);
});
myPromise
.then(() => {
console.log("getting here too");
firebase.database().ref(`collection/${idNode}`).set(inputs);
})
.then(() => {
console.log("all is set");
})
.catch((err) => {
console.log(err);
});
if i run the program, the first part of the promise is executing but all .then() functions arent executing. how do i fix this?
In this scheme, the promise callback has one (resolve) or two (resolve,reject) arguments.
let p = new Promise((resolve, reject)=> {
//do something
//resolve the promise:
if (result === "ok") {
resolve(3);
}
else {
reject("Something is wrong");
}
});
p.then(res => {
console.log(res); // "3"
}).catch(err => {
console.error(err); //"Something is wrrong
});
Of course, nowadays you can use async + await in a lot of cases.
You need to resolve the promise, using resolve() and also return the promise from firebase so the next .then in the chain works properly.
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("getting here");
// You have to call resolve for all `.then` methods to be triggered
resolve({ ...inputs, images: imageAsUrl });
}, 100);
});
myPromise
.then((inputs) => {
console.log("getting here too");
// You have to return a promise in a .then function for the next .then to work properly
return firebase.database().ref(`collection/${idNode}`).set(inputs);
})
.then(() => {
console.log("all is set");
})
.catch((err) => {
console.log(err);
});
I am working on a Discord bot and need to return a value after the reaction promise finishes.
function sendDM(userTag) {
let sentMessage = undefined;
let moderator = undefined;
let status = "";
try {
client.users.fetch(userTag, false).then((user) => {
user.send("User Authentication Request -\n```Discord Tag:" + userTag + "\n" + "Date Sent: " + getDate() + "\n" + "```" + "Authorize?").then((message => {
moderator = user
sentMessage = message
message.react("✅");
message.react("❌");
}));
})
client.on("messageReactionAdd", (reaction, user) => {
if (reaction.emoji.name == "✅") {
const authorTag = client.users.cache.find(u => u.tag === moderator.tag);
if (user.id == authorTag) {
status = "complete";
console.log("Auth Request Complete");
moderator.send("Authentication request was successful.");
}
} else {
if (reaction.emoji.name == "❌") {
const authorTag = client.users.cache.find(u => u.tag === moderator.tag);
if (user.id == authorTag) {
status = "dropped";
console.log("Auth Request Dropped: User Denied");
moderator.send("Authentication request was dropped.");
}
}
}
}).then(someShit => console.log("test: " + someShit))
} catch(error) {
console.log("DM ERROR_" + error);
}
// Return would be here
}
The problem is once the by the time the user reacts, the function has already returned the empty "status" string.
I'm not an expert in the field, but it looks like you could wrap your code block in a Promise and wait until the promise has been resolved by your code. Something like this might work:
async function sendDM(userTag) {
let sentMessage = undefined;
let moderator = undefined;
let status = "";
const statusPromise = new Promise((resolve, reject) => {
try {
client.users.fetch(userTag, false).then((user) => {
user
.send(
"User Authentication Request -\n```Discord Tag:" +
userTag +
"\n" +
"Date Sent: " +
getDate() +
"\n" +
"```" +
"Authorize?"
)
.then((message) => {
moderator = user;
sentMessage = message;
message.react("✅");
message.react("❌");
});
});
client
.on("messageReactionAdd", (reaction, user) => {
if (reaction.emoji.name == "✅") {
const authorTag = client.users.cache.find(
(u) => u.tag === moderator.tag
);
if (user.id == authorTag) {
resolve("complete");
console.log("Auth Request Complete");
moderator.send("Authentication request was successful.");
}
} else {
if (reaction.emoji.name == "❌") {
const authorTag = client.users.cache.find(
(u) => u.tag === moderator.tag
);
if (user.id == authorTag) {
resolve("dropped");
console.log("Auth Request Dropped: User Denied");
moderator.send("Authentication request was dropped.");
}
}
}
})
.then((someShit) => console.log("test: " + someShit));
} catch (error) {
console.log("DM ERROR_" + error);
reject(error);
}
});
status = await statusPromise;
// Return would be here
}
This might introduce problems elsewhere in your code since you have to make your function async to use the await keyword, but this way your code should wait until a value has been returned from the promise.
Use async/await to halt the execution of the function until the promise has resolved:
async function sendDM(userTag) {
...
await client.on("messageReactionAdd", (reaction, user) => {
...
// Promise has resolved so the data is available
}
Updated with Promise example.
I'm running NodeJS and are having issues with multiple if-statements and return-statements.
I'm trying to use Promise at it might seem as a way to go.
This is my example code:
const express = require('express');
const app = express();
const pgPromise = require('pg-promise')();
const db = pgPromise(CONNECTION_STRING);
app.use((req, res) => {
var message = "";
promise1 = new Promise((resolve, reject) => {
message += "promise1";
if (false) {
reject(message);
}
});
promise2 = new Promise((resolve, reject) => {
if (true) {
db.one('SELECT 1')
.then(row => {
message += " promise2";
resolve(message);
})
.catch(err => {
message += " error";
reject(message);
});
}
});
var printResult = (results) => {console.log("Results = ", results, "message = ", message)}
Promise.all([promise1, promise2]).then(printResult);
return res.json({ message: message });
});
app.listen(3000);
It doesn't seem to wait for the Promise 2 to finish the database query.
How can I make sure the database query is done before return any statement?
The code execution doesn't stop on Promise.all, you need to move the return statement to the Promise.all callback, and return the Promise returned by Promise.all.
return Promise.all([promise1, promise2]).then(() => {
printResult();
return res.json({ message: message });
});
Since Node JS runs asynchronously it doesn't wait for input1, inpu2, input3 to finish before executing final line(return res.json({ error: false });).
You need to use Promise to handle the sequence. Find the code below.
let input1 = new Promise(function (resolve, reject) {
if (typeof req.body.input1 != "undefined") {
// do something
resolve('Success');
} else {
reject('Error');
}
});
let input2 = new Promise(function (resolve, reject) {
if (typeof req.body.input2 != "undefined") {
// do something
resolve('Success');
} else {
reject('Error');
}
});
let input3 = new Promise(function (resolve, reject) {
if (typeof req.body.input3 != "undefined") {
// do something
resolve('Success');
} else {
reject('Error');
}
});
input1.then((value) => {
return res.json({ error: true });
})
.catch((e) => {
input2.then((value) => {
return res.json({ error: true });
})
.catch((e) => {
input3.then((value) => {
return res.json({ error: true });
})
.catch((e) => {
return res.json({ error: false });
})
})
})
If you want to handle all inputs asynchronously, use promise.all().
I asked a question two days ago with a reply "Your method must return a Promise (or an Observable)."
I have altered my code to be exactly the same as the example at "https://firebase.google.com/docs/firestore/manage-data/transactions" but the problem is it passes the result as a console log but I need to wait for the write to complete at I need the result.
orderIndex() {
let db = this.firebase.firestore();
var sfDocRef = db.collection("cities").doc("SF");
db.runTransaction(function (transaction) {
return transaction.get(sfDocRef).then(function (sfDoc) {
if (!sfDoc.exists) {
throw "Document does not exist!";
}
var newPopulation = sfDoc.data().population + 1;
if (newPopulation <= 1000000) {
transaction.update(sfDocRef, { population: newPopulation });
return newPopulation;
} else {
return Promise.reject("Sorry! Population is too big.");
}
});
}).then(function (newPopulation) {
console.log("Population increased to ", newPopulation);
}).catch(function (err) {
// This will be an "population is too big" error.
console.error(err);
});
}
I have spent a further two days trying to get a promise returned.
I have seen so many questions asking for help and receiving code suggestions in reply. Please help because I am new to this and have spent over four days on this problem.
By the way the code from firebase.google has an error in
return Promise.reject("Sorry! Population is too big.");
Error: "[ts] Property 'reject' does not exist on type '(resolver: (resolve: (val: IWhenable) => void, reject: (reason: any) => void, notify: (prog...'."
My previous question was at "How do I alter the promises in my function to stop it returning before the data arrives?"
Your function is not returning the promise and also in the then case you are not returning any value.
Try this:
orderIndex() {
let db = this.firebase.firestore();
var sfDocRef = db.collection("cities").doc("SF");
return db.runTransaction(function (transaction) { //Return here
return transaction.get(sfDocRef).then(function (sfDoc) {
if (!sfDoc.exists) {
throw "Document does not exist!";
}
var newPopulation = sfDoc.data().population + 1;
if (newPopulation <= 1000000) {
transaction.update(sfDocRef, { population: newPopulation });
return newPopulation;
} else {
return Promise.reject("Sorry! Population is too big.");
}
});
}).then(function (newPopulation) {
console.log("Population increased to ", newPopulation);
return newPopulation; //Return the value
}).catch(function (err) {
// This will be an "population is too big" error.
console.error(err);
});
}
The following code updates the index, stores it back in firestore and returns the new number.
createOrderNo() {
const getDbIndex = new Promise(
(resolve, reject) => {
if (!this.orderLive) {
this.orderLive = true;
const sfDocRef = this.db.collection('eOrderIndex').doc('orderIndex');
sfDocRef.get().
then(function (sfDoc) {
if (!sfDoc.exists) {
throw "Document does not exist!";
}
console.log('sfDoc.data()', sfDoc.data()['index'])
let index = sfDoc.data()['index'] + 1;
sfDocRef.update({ index: index });
resolve(index);
})
} else {
const reason = new Error('Already live');
reject(reason);
}
})
async function show(index) {
return new Promise(
(resolve, reject) => {
var message = 'New index ' + index;
resolve(message);
}
);
};
// call the promise
async function runPromise() {
try {
console.log('Before get');
let index = await getDbIndex;
let message = await show(index);
console.log(message);
console.log('After get');
}
catch (error) {
console.log(error.message);
}
}
(async () => {
await runPromise();
})();
}
Many thanks to Jecelyn Yeen at scotch.io
I'm trying to get Number 1 to console.log first but it's not. What am I doing wrong?
Thank you.
let timer = function(time, message) {
setTimeout((time) => {
console.log(`ALERT: ${message}`);
}, time);
//return time;
}
const asyncDemo = async function asyncDemo(time, message) {
try {
var time1 = await timer(3000, "Number 1");
} catch (e) {
console.log("Critical error!");
}
try {
var time2 = await timer(1000, "Number 2");
} catch (e) {
console.log("Critical error!");
}
}
asyncDemo();
Ansync/Await depends on promises to work. So your function needs to return a promise. For instance:
let timer = function(time, message) {
return new Promise((resolve, reject) =>{
setTimeout((time) => {
console.log(`ALERT: ${message}`);
resolve()
}, time);
})
}